// import { Component, Vec2 } from 'cc'

// export class Tools {
//   static readonly instance: Tools = new Tools()

//   static _sharedComp: Component = null

//   private cachedVec2: Vec2 = Vec2.ZERO

//   constructor() {
//     String.prototype['format'] = function (args) {
//       if (arguments.length > 0) {
//         let result: string = this
//         if (arguments.length == 1 && args && typeof args == 'object') {
//           let count = 0
//           const call = param => {
//             if (Array.isArray(param)) {
//               for (let k = 0; k < param.length; k++) {
//                 call(param[k])
//               }
//             } else {
//               const reg = new RegExp(`({[${count}]})`, 'g')
//               result = result.replace(reg, param)
//               count++
//             }
//           }
//           for (let i = 0; i < args.length; i++) {
//             call(args[i])
//           }
//         } else {
//           for (let i = 0; i < arguments.length; i++) {
//             if (arguments[i] == undefined) {
//               return ''
//             }

//             const reg = new RegExp(`({[${i}]})`, 'g')
//             result = result.replace(reg, arguments[i])
//           }
//         }
//         return result
//       }
//       return this
//     }

//     if (window) {
//       window['DYTools'] = this
//     }
//   }

//   public get sharedComp(): Component {
//     if (!Tools._sharedComp) {
//       const node = new Node()
//       game.addPersistRootNode(node)
//       Tools._sharedComp = node.addComponent(Component)
//     }
//     return Tools._sharedComp
//   }
//   //切服或者登录不需要清楚的数据
//   public needToSave() {
//     let savaDataArr = GConfig.saveDataArr
//     let statusArr = []
//     for (let i = 0; i < savaDataArr.length; i++) {
//       statusArr[i] = sys.localStorage.getItem(savaDataArr[i]) || 'false'
//     }
//     sys.localStorage.clear()
//     for (let i = 0; i < statusArr.length; i++) {
//       sys.localStorage.setItem(savaDataArr[i], statusArr[i])
//     }
//   }
//   public scheduleOnce(callback: Function, delay?: number) {
//     this.sharedComp.scheduleOnce(callback, delay)
//   }

//   public sleep(time: number): Promise<any> {
//     return new Promise((resolve, reject) => {
//       setTimeout(() => {
//         resolve(1)
//       }, time)
//     })
//   }

//   /** 按钮点击间隔 */
//   private _btnAble = true

//   public isBtnClickedAble(audio = true, time = 200) {
//     if (this._btnAble) {
//       this._btnAble = false
//       setTimeout(() => {
//         this._btnAble = true
//       }, time)
//       if (audio) {
//         FrameMgr.audioMgr.playEffect('ui_click')
//       }
//       return true
//     }
//     return false
//   }

//   /**
//    * 获取当前系统时间戳
//    */
//   public getPhoneTimestamp(): number {
//     // let date = new Date();
//     // return Date.parse(date.toString());
//     return new Date().getTime()
//   }

//   /** 获取当前时间戳 */
//   public getCurTimestamp(): number {
//     return Math.floor(GData.timestamp)
//     // return this.getPhoneTimestamp();
//   }

//   /** 获取北京时间 */
//   public getDateForTimeZone(timestamp: number, timezone = 8) {
//     const date = new Date(timestamp)
//     // console.log('aaaaaaaa 11', lastDate.toString(), lastDate.getTimezoneOffset());
//     date.setTime(date.getTime() + date.getTimezoneOffset() * 60000) // 修正为UTC
//     date.setTime(date.getTime() + timezone * 3600000) // 转换为特定时区
//     return date
//   }

//   /** 是否同一天 */
//   public isSameDay(timeStamp: number, b?: number, timezone = 8) {
//     const lastDate = this.getDateForTimeZone(timeStamp, timezone)
//     const lastYear = lastDate.getFullYear()
//     const lastMonth = lastDate.getMonth()
//     const lastDay = lastDate.getDate()
//     // const lastHour = lastDate.getHours();
//     // const lastMinute = lastDate.getMinutes();
//     // const lastsSecond = lastDate.getSeconds();
//     // console.log('aaaaaaaa 22', lastDate.toString(), lastDate.getTimezoneOffset());

//     b = b ?? this.getCurTimestamp()
//     const date = this.getDateForTimeZone(b, timezone)
//     const year = date.getFullYear()
//     const month = date.getMonth()
//     const day = date.getDate()
//     // const hour = date.getHours();
//     // const min = date.getMinutes();
//     // const sec = date.getSeconds();
//     // console.log('aaaaaaaa 44', date.toString(), date.getTimezoneOffset());

//     return lastYear === year && month === lastMonth && day == lastDay
//   }

//   /**
//    * 今天距离某个时间点是否是之后的某一天
//    * @param a 时间戳(某个时间点)
//    */
//   public isLaterDay(a: number, b?: number, timezone = 8) {
//     let ret = false

//     const lastDate = this.getDateForTimeZone(a, timezone)
//     const lastYear = lastDate.getFullYear()
//     const lastMonth = lastDate.getMonth()
//     const lastDay = lastDate.getDate()

//     b = b ?? this.getCurTimestamp()
//     const date = this.getDateForTimeZone(b, timezone)
//     const year = date.getFullYear()
//     const month = date.getMonth()
//     const day = date.getDate()

//     if (lastYear != year) {
//       if (lastYear < year) {
//         ret = true
//       }
//     } else if (lastMonth != month) {
//       if (lastMonth < month) {
//         ret = true
//       }
//     } else if (lastDay < day) {
//       ret = true
//     }

//     return ret
//   }

//   /** 获取2个时间戳之间天数（东8区）--注意，这里的start和end只能是服务器下发的时间戳（否则，可能有问题--冬令时夏令时转换） */
//   public getRealDiffDays(start: number, end: number, timezone = 8) {
//     if (start > end) {
//       return -1
//     }
//     const diff = end - start
//     /** 天数 */
//     let days = Math.floor(diff / (24 * 60 * 60 * 1000))

//     /** 天数整除后，剩余时间戳 */
//     const leftTime = diff - days * (24 * 60 * 60 * 1000)

//     /** 开始时间戳距离当天24点差值 */
//     const startDate = this.getDateForTimeZone(start, timezone)
//     const hour = startDate.getHours()
//     const minute = startDate.getMinutes()
//     const sec = startDate.getSeconds()

//     const secDiff = 60 - sec
//     const minDiff = 59 - minute
//     const hourDiff = 23 - hour
//     const startDiff = hourDiff * (60 * 60 * 1000) + minDiff * (60 * 1000) + secDiff * 1000

//     /** 结束时间戳距离当天0点差值 */
//     // let endDate = new Date(end);
//     // hour = endDate.getHours();
//     // minute = endDate.getMinutes();
//     // sec = endDate.getSeconds();
//     // let endDiff = hour * (60 * 60 * 1000) + minute * (60 * 1000) + sec * 1000;

//     /** 剩余时间戳是否大于时间戳 */
//     if (leftTime >= startDiff) {
//       /** 大于则说明跨天 */
//       days += 1
//     }

//     return days
//   }

//   public consoleStack() {
//     try {
//       // 这里放置可能会抛出错误的代码
//       // 如果发生错误，控制流会转到catch块
//       throw new Error('堆栈信息')
//     } catch (error) {
//       // 打印错误信息和堆栈信息
//       console.warn(error.message)
//       console.warn(error.stack)
//     }
//   }

//   /**
//    * 是否满足刷新条件
//    * @param timeStamp 时间戳
//    * @param hour 刷新时间点
//    */
//   // public isLaterDayRefresh(timeStamp: number, hour: number) {
//   //     let ret = false;

//   //     const diffTimestamp = this.getCurTimestamp() - timeStamp;
//   //     if (diffTimestamp > 0) {
//   //         const diffHour = Math.floor(diffTimestamp / 3600000);
//   //         if (diffHour > 24) {
//   //             ret = true;
//   //         } else {
//   //             const lastDate = new Date(timeStamp);
//   //             const lastDay = lastDate.getDate();
//   //             const lastHour = lastDate.getHours();

//   //             const curDate = new Date(this.getCurTimestamp());
//   //             const curDay = lastDate.getDate();
//   //             const curHour = curDate.getHours();

//   //             // 非0点刷新
//   //             if (hour > 0) {
//   //                 // 不同天
//   //                 if (lastDay < curDay) {
//   //                     if (curHour >= hour) {
//   //                         ret = true;
//   //                     }
//   //                 } else if (lastDay == curDay) {
//   //                     // 同一天
//   //                     if (curHour >= hour && lastHour < hour) {
//   //                         ret = true;
//   //                     }
//   //                 }
//   //             } else {
//   //                 // 0点刷新
//   //                 if (lastDay < curDay) {
//   //                     ret = true;
//   //                 }
//   //             }
//   //         }
//   //     }

//   //     return ret;
//   // }

//   /**
//    * 是否第二天
//    * @param timeStamp
//    */
//   // public isNextDay(timeStamp: number) {
//   //     let ret = false;

//   //     const lastDate = new Date(timeStamp);
//   //     let hour = lastDate.getHours();
//   //     let minute = lastDate.getMinutes();
//   //     let second = lastDate.getSeconds();

//   //     // 距离24点
//   //     hour = 23 - hour;
//   //     minute = 59 - minute;
//   //     second = 60 - second;

//   //     let targetMin = hour * 3600 + minute * 60 + second;
//   //     let targetMax = targetMin + 24 * 3600;
//   //     targetMin = timeStamp + targetMin * 1000;
//   //     targetMax = timeStamp + targetMax * 1000;

//   //     const curTime = this.getCurTimestamp();
//   //     if (targetMin <= curTime && targetMax > curTime) {
//   //         ret = true;
//   //     }

//   //     return ret;
//   // }

//   /** 两个时间戳实际日期差(start必须小于end) -- 注意：该接口不可调用，只是打点在用，用的当地时区时间 */
//   public getDiffDays(start: number, end: number) {
//     if (start > end) {
//       return -1
//     }
//     const diff = end - start
//     /** 天数 */
//     let days = Math.floor(diff / (24 * 60 * 60 * 1000))

//     /** 天数整除后，剩余时间戳 */
//     const leftTime = diff - days * (24 * 60 * 60 * 1000)

//     /** 开始时间戳距离当天24点差值 */
//     const startDate = new Date(start)
//     const hour = startDate.getHours()
//     const minute = startDate.getMinutes()
//     const sec = startDate.getSeconds()

//     const secDiff = 60 - sec
//     const minDiff = 59 - minute
//     const hourDiff = 23 - hour
//     const startDiff = hourDiff * (60 * 60 * 1000) + minDiff * (60 * 1000) + secDiff * 1000

//     /** 结束时间戳距离当天0点差值 */
//     // let endDate = new Date(end);
//     // hour = endDate.getHours();
//     // minute = endDate.getMinutes();
//     // sec = endDate.getSeconds();
//     // let endDiff = hour * (60 * 60 * 1000) + minute * (60 * 1000) + sec * 1000;

//     /** 剩余时间戳是否大于时间戳 */
//     if (leftTime >= startDiff) {
//       /** 大于则说明跨天 */
//       days += 1
//     }

//     return days
//   }

//   /**
//    * log输出
//    * @param txt
//    */
//   public log(message?: any, ...optionalParams: any[]) {
//     if (!GConfig.isPublish && GConfig.logAble) {
//       if (CC_JSB) {
//         // 手机上日志超过一定长度会被截断，分批进行输出
//         const logLimit = 1000
//         while (message?.length > 0) {
//           if (message.length > logLimit) {
//             console.log(message.substring(0, logLimit))
//             message = message.substring(logLimit)
//           } else {
//             console.log(message, ...optionalParams)
//             message = null
//           }
//         }
//       } else {
//         console.log(message, ...optionalParams)
//       }
//     }
//   }

//   /**
//    * error输出
//    * @param txt
//    */
//   public error(message?: any, ...optionalParams: any[]) {
//     console.error(message, ...optionalParams)
//   }

//   /**
//    * warn输出
//    * @param txt
//    */
//   public warn(message?: any, ...optionalParams: any[]) {
//     if (!GConfig.isPublish) console.warn(message, ...optionalParams)
//   }

//   /*
//    * 功能：随机数，整形区间随机(闭区间)
//    * 参数：最小值，最大值(整数)
//    */
//   public random_int(min: number, max: number): number {
//     if (min > max) {
//       const temp = max
//       max = min
//       min = temp
//     }
//     const diff = max - min
//     const value = min + (diff + 1) * Math.random()
//     let result = Math.floor(value)

//     if (result < min) {
//       result = min
//     } else if (result > max) {
//       result = max
//     }

//     return result
//   }

//   /**根据权重数组返回随机索引 */
//   public randomWeight(weightList: number[]) {
//     let totalWeight = 0
//     for (let index = 0; index < weightList.length; index++) {
//       const element = weightList[index]
//       totalWeight += element
//     }
//     let randValue = this.random_int(1, totalWeight)
//     const randValue2 = randValue
//     for (let index = 0; index < weightList.length; index++) {
//       if (randValue <= weightList[index]) {
//         return index
//       }
//       randValue -= weightList[index]
//     }
//     return -1
//   }

//   /**
//    * 概率触发
//    */
//   public probabilityTrigger(probability: number): boolean {
//     if (probability <= 0) {
//       return false
//     }
//     if (probability >= 100) {
//       return true
//     }
//     const value = this.random_int(0, 99)
//     if (probability > value) {
//       return true
//     }
//     return false
//   }

//   /**
//    * 获取随机坐标
//    * @param xRange x范围
//    * @param yRange y范围
//    */
//   public getRandomVec2(xRange: Vec2, yRange: Vec2) {
//     const x = this.random_int(xRange.x, xRange.y)
//     const y = this.random_int(yRange.x, yRange.y)
//     return v2(x, y)
//   }

//   /**
//    * 获取自定义字典长度
//    * @param dict 字典 {[key:number]:any}
//    */
//   public getDictLength(dict: { [key: number]: any }) {
//     let length = 0
//     if (dict) {
//       for (const key in dict) {
//         const value = dict[key]
//         if (value != null) {
//           length++
//         }
//       }
//     }
//     return length
//   }

//   /**
//    * 获取字符串分隔后的某个元素
//    * @param str
//    * @param separator
//    * @param index
//    */
//   public getStringDivideForIndex(str: string, separator: string, index: number) {
//     const arr = str.split(separator)
//     if (index >= 0 && arr.length > index) {
//       return arr[index]
//     }
//     return null
//   }

//   /**
//    * 将字符串转换为坐标
//    * @param str 字符串
//    * @param separator 分隔符
//    */
//   public stringToPoint(str: string, separator = '*'): Vec2 {
//     const pos = Vec2.ZERO
//     if (str != '') {
//       const arr = str.split(separator)
//       if (arr.length > 0) {
//         pos.x = Number(arr[0])
//       }
//       if (arr.length > 1) {
//         pos.y = Number(arr[1])
//       }
//     }
//     return pos
//   }

//   public stringToVec2Arr(str: string): Vec2[] {
//     const ret = []
//     if (str && str != '') {
//       const arr = str.split('#')
//       for (let i = 0; i < arr.length; i++) {
//         const tmp = this.stringToPoint(arr[i], '*')
//         ret.push(tmp)
//       }
//     }
//     return ret
//   }

//   /** 一维数组转换为向量(数组长度为0时返回null, 数组长度为1时返回(arr[0], 0), 数组长度大于2时返回(arr[0], arr[1]) */
//   public numArrToVec2(arr: number[]): Vec2 {
//     if (arr && arr.length > 0) {
//       const x = arr[0]
//       const y = arr[1] || 0
//       return v2(x, y)
//     }
//     return null
//   }

//   /** 二维数组转换为向量数组 */
//   public numArrToVec2Arr(arr: number[][]): Vec2[] {
//     const ret: Vec2[] = []
//     for (let i = 0; i < arr?.length; i++) {
//       const tmp = arr[i]
//       const vec = this.numArrToVec2(tmp)
//       if (vec) {
//         ret.push(vec)
//       }
//     }
//     return ret
//   }

//   /**
//    * 将字符串转换为尺寸
//    * @param str 字符串
//    * @param separator 分隔符
//    */
//   public stringToSize(str: string, separator = '*'): Size {
//     let size = Size.ZERO
//     if (str != '') {
//       const arr = str.split(separator)
//       if (arr.length > 1) {
//         size = size(Number(arr[0]), Number(arr[1]))
//       }
//     }
//     return size
//   }

//   /**
//    * 将字符串转换为数字
//    * @param str
//    * @param separator 分隔符
//    */
//   public stringToNumber(str: string, separator = '*'): number[] {
//     const ret: number[] = []
//     if (str !== undefined && str !== null) {
//       str = str.toString()
//       const arr = str.split(separator)
//       for (let i = 0; i < arr.length; i++) {
//         const ss = arr[i]
//         if (ss != '') {
//           ret.push(Number(ss))
//         }
//       }
//     }
//     return ret
//   }

//   /**
//    * 将字符串转换为二维数组
//    * @param str
//    * @param separator 分隔符
//    */
//   public stringToNumberArr(str: string, sp1 = '#', sp2 = '*'): number[][] {
//     const ret: number[][] = []
//     if (str !== undefined && str !== null && str.length > 0) {
//       str = str.toString()
//       const arr = str.split(sp1)
//       for (let i = 0; i < arr.length; i++) {
//         const arr2: number[] = []
//         const tmp = arr[i].split(sp2)
//         for (let j = 0; j < tmp.length; j++) {
//           const ss = tmp[j]
//           if (ss != '') {
//             arr2.push(Number(ss))
//           }
//         }
//         ret.push(arr2)
//       }
//     }
//     return ret
//   }

//   /**
//    * 将字符串转换为二维数组
//    * @param str
//    * @param separator 分隔符
//    */
//   public stringToObj(str: string, sp1 = '#', sp2 = '*'): any {
//     const ret = {}
//     if (str !== undefined && str !== null) {
//       str = str.toString()
//       const arr = str.split(sp1)
//       for (let i = 0; i < arr.length; i++) {
//         const arr2 = []
//         const tmp = arr[i].split(sp2)
//         ret[Number(tmp[0])] = tmp[1]
//       }
//     }
//     return ret
//   }

//   /**
//    * 两个坐标距离
//    * @param v1
//    * @param v2
//    */
//   public getDisForVec2(v1: Vec2, v2: Vec2): number {
//     if (v1 && v2) {
//       const diff = v1.sub(v2)
//       return diff.mag()
//     }
//     return 0
//   }

//   /**
//    * 获取2个坐标距离
//    * @param v1 vec2 或者 vec3
//    * @param v2 vec2 或者 vec3
//    */
//   public getDisForVec(v1: any, v2: any): number {
//     if (v1 && v2) {
//       const diffX = v1.x - v2.x
//       const diffY = v1.y - v2.y

//       return Math.sqrt(diffX * diffX + diffY * diffY)
//     }
//     return 0
//   }

//   /**
//    * 点到直线距离
//    * @param point 点
//    * @param lp0 直线坐标点1
//    * @param lp1 直线坐标点2
//    */
//   public getDisFromPointToLine(point: Vec2, lp0: Vec2, lp1: Vec2): number {
//     const p = v2(point.x, point.y)
//     const v1 = p.sub(lp0)
//     const v2 = lp1.sub(lp0)
//     const a1 = this.getSignAngle(v1, v2)

//     const d1 = v1.mag()
//     const dis = d1 * Math.sin(a1)

//     return dis
//   }

//   /**
//    * 点竖向移动到某条直线竖向偏移
//    * @param point
//    * @param lp0
//    * @param lp1
//    */
//   public getPointToLineY(point: Vec2, lp0: Vec2, lp1: Vec2): number {
//     const a = (lp0.y - lp1.y) / (lp0.x - lp1.x)
//     const b = lp0.y - a * lp0.x

//     const py = a * point.x + b
//     const dy = py - point.y

//     return dy
//   }

//   /**
//    * !#en Test line and line
//    * !#zh 测试线段与线段是否相交
//    * @method lineLine
//    * @param {Vec2} a1 - The start point of the first line
//    * @param {Vec2} a2 - The end point of the first line
//    * @param {Vec2} b1 - The start point of the second line
//    * @param {Vec2} b2 - The end point of the second line
//    * @return {boolean}
//    */
//   public isLineLine(a1: Vec2, a2: Vec2, b1: Vec2, b2: Vec2) {
//     const u_b = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y)

//     if (u_b !== 0) {
//       do {
//         const ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x)
//         const ua = ua_t / u_b
//         if (ua < 0 || ua > 1) {
//           break
//         }

//         const ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x)
//         const ub = ub_t / u_b

//         if (ub >= 0 && ub <= 1) {
//           return true
//         }
//       } while (0)
//     }

//     return false
//   }

//   /**
//    * 获取线段交点
//    * @param 线段起点1，线段终点1，线段起点2，线段终点2
//    * @return 交点坐标(null不相交)
//    */
//   public getLineCrossPoint(a: Vec2, b: Vec2, c: Vec2, d: Vec2): Vec2 {
//     // 三角形abc 面积的2倍
//     const area_abc = (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x)

//     // 三角形abd 面积的2倍
//     const area_abd = (a.x - d.x) * (b.y - d.y) - (a.y - d.y) * (b.x - d.x)

//     // 面积符号相同则两点在线段同侧,不相交 (对点在线段上的情况,本例当作不相交处理);
//     if (area_abc * area_abd >= 0) {
//       return null
//     }

//     // 三角形cda 面积的2倍
//     const area_cda = (c.x - a.x) * (d.y - a.y) - (c.y - a.y) * (d.x - a.x)
//     // 三角形cdb 面积的2倍
//     // 注意: 这里有一个小优化.不需要再用公式计算面积,而是通过已知的三个面积加减得出.
//     const area_cdb = area_cda + area_abc - area_abd
//     if (area_cda * area_cdb >= 0) {
//       return null
//     }

//     //计算交点坐标
//     const t = area_cda / (area_abd - area_abc)
//     const dx = t * (b.x - a.x)
//     const dy = t * (b.y - a.y)
//     return v2(a.x + dx, a.y + dy)
//   }

//   /**
//    * 设置网络图片
//    */
//   // public setUrlFrame(path: string, spr: Sprite, callback: any = null) {
//   //     if (path == undefined || path == null || path == "") {
//   //         return;
//   //     }
//   //     loader.load({ url: path, type: 'png' }, function (err, tex) {
//   //         if (err) {
//   //             this.error(err.message || err);
//   //             return;
//   //         }
//   //         let frame = new SpriteFrame(tex);
//   //         spr.spriteFrame = frame;
//   //         if (callback) {
//   //             callback();
//   //         }
//   //     }.bind(this));
//   // }

//   /**
//    * 截取字符串前n位
//    * @param str
//    * @param count
//    */
//   public getLimitStr(str: string, count: number, omit = '...') {
//     const strCount = this.getStringCharacterLength(str)
//     if (strCount > count) {
//       const tempStr = this.subStrByCharacter(str, count)
//       const useStr = `${tempStr}${omit}`
//       return useStr
//     }

//     return str
//   }

//   /**
//    * 得到字符串的字字符长度（中文占2字符）
//    * @param str 字符串
//    */
//   public getStringCharacterLength(str: string): number {
//     let codeCount = 0
//     let charCode = -1
//     if (str) {
//       for (let i = 0; i < str.length; i++) {
//         charCode = str.charCodeAt(i)
//         if (charCode >= 0 && charCode <= 128) {
//           codeCount += 1
//         } else {
//           codeCount += 2
//         }
//       }
//     }
//     return codeCount
//   }

//   /**
//    * 截取制定字符长度的字符串
//    * @param str 源字符串
//    * @param length 截取长度（中文占用2个字符）
//    */
//   public subStrByCharacter(str: string, length: number) {
//     let index = 0
//     let codeCount = 0
//     let charCode = -1
//     for (let i = 0; i < str.length; i++) {
//       charCode = str.charCodeAt(i)
//       if (charCode >= 0 && charCode <= 128) {
//         codeCount += 1
//       } else {
//         codeCount += 2
//       }
//       if (codeCount > length) {
//         break
//       }
//       index += 1
//     }
//     return str.substring(0, index)
//   }

//   /**
//    * 过滤特殊字符和emoji表情字符
//    * @param inputString 源字符串
//    * @param isFilterSpecial 是否去除特殊字符，默认不去除
//    */
//   public filterSpecialChar(inputString: string, isFilterSpecial = false): string {
//     let subString = inputString
//     if (isFilterSpecial) {
//       const pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>《》/?~！@#￥……&*（）——|{}【】‘；：”“'。，、？]")
//       // 过滤特殊字符
//       subString = inputString.replace(pattern, '')
//       let tmpString = inputString
//       while (subString != tmpString) {
//         tmpString = subString
//         subString = subString.replace(pattern, '')
//       }
//       // console.log(`after fileter special char:${subString}`);
//     }

//     // emoji表情字符过滤
//     const rep =
//       /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g
//     subString = subString.replace(rep, '')
//     // console.log(`after fileter special char:${subString}`);
//     return subString
//   }

//   /**
//    * 数字差比较
//    * @param num1
//    * @param num2
//    */
//   public numberDiffAbs(num1: number, num2: number) {
//     return Math.abs(num1 - num2)
//   }

//   public numberDiff(num1: number, num2: number) {
//     return num1 - num2
//   }

//   public isNumberDiffRange(num1: number, num2: number, range: number) {
//     return this.numberDiffAbs(num1, num2) <= range
//   }

//   public isAbsNumDiffRange(num1: number, num2: number, range: number) {
//     const ab1 = Math.abs(num1)
//     const ab2 = Math.abs(num2)
//     const diff = Math.abs(ab1 - ab2)
//     return diff <= range
//   }

//   /**
//    * 根据符号, 修改传入数值
//    * @param num 原数值
//    * @param sign 符号(1或-1)
//    */
//   public modifyNumBySign(num: number, sign: number) {
//     if ((num >= 0 && sign >= 0) || (num < 0 && sign < 0)) {
//       // 同号
//       return num
//     }

//     // 异号
//     return Math.abs(num) * sign
//   }

//   /**
//    * 坐标双方向差是否再某个范围内
//    * @param pos1
//    * @param pos2
//    * @param range
//    */
//   public isVecDiffRange(pos1: Vec2 | Vec3, pos2: Vec2 | Vec3, range: number) {
//     return Math.abs(pos1.x - pos2.x) <= range && Math.abs(pos1.y - pos2.y) <= range
//   }

//   public isVecDiffVecRange(pos1: Vec2 | Vec3, pos2: Vec2 | Vec3, vec: Vec2 | Vec3) {
//     return Math.abs(pos1.x - pos2.x) <= vec.x && Math.abs(pos1.y - pos2.y) <= vec.y
//   }

//   /**
//    * 数字转成字符串,会取整,不保留小数
//    * @param num
//    */
//   public numberToString3(num: number) {
//     num = Math.floor(num)
//     let str = ''
//     let sysbol = ''
//     if (num < 1000) {
//       str = num.toString()
//     } else {
//       let a = 0
//       if (num >= 1000000) {
//         a = Math.floor(num / 1000000)
//         sysbol = 'm'
//         str = a + sysbol
//       } else if (num >= 1000) {
//         a = Math.floor(num / 1000)
//         sysbol = 'k'
//         str = a + sysbol
//       }
//     }
//     return str
//   }

//   /**
//    * 数字转成字符串,会取整,并只保留一位数字
//    * @param num
//    */
//   public numberToString2(num: number) {
//     num = Math.floor(num)
//     let str = ''
//     let sysbol = ''
//     if (num < 10000) {
//       str = num.toString()
//     } else {
//       let a = 0
//       let b = 0
//       //let c = 0;
//       if (num >= 1000000000) {
//         a = Math.floor(num / 1000000000)
//         b = Math.floor((num % 1000000000) / 100000000)
//         //c = Math.floor(num % 100000 / 10000);
//         sysbol = 'b'
//       } else if (num >= 1000000) {
//         a = Math.floor(num / 1000000)
//         b = Math.floor((num % 1000000) / 100000)
//         //c = Math.floor(num % 100000 / 10000);
//         sysbol = 'm'
//       } else if (num >= 1000) {
//         a = Math.floor(num / 1000)
//         b = Math.floor((num % 1000) / 100)
//         //c = Math.floor(num % 100 / 10);
//         sysbol = 'k'
//       }

//       if (a > 99) {
//         str = a.toString()
//       } else if (b > 0) {
//         str = `${a}.${b}`
//       } else {
//         str = a.toString()
//       }
//     }
//     return str + sysbol
//   }

//   /**
//    * 数字转成字符串,会取整,并只保留一位小数数字
//    * @param num
//    */
//   public numberToString6(num: number) {
//     //num = Math.floor(num);
//     let str = ''
//     let sysbol = ''
//     if (num < 10000) {
//       str = num.toString()
//     } else {
//       let a = 0
//       let b = 0
//       //let c = 0;
//       if (num >= 1000000000) {
//         a = Math.floor(num / 1000000000)
//         b = Math.floor((num % 1000000000) / 100000000)
//         //c = Math.floor(num % 100000 / 10000);
//         sysbol = 'b'
//       } else if (num >= 1000000) {
//         a = Math.floor(num / 1000000)
//         b = Math.floor((num % 1000000) / 100000)
//         //c = Math.floor(num % 100000 / 10000);
//         sysbol = 'm'
//       } else if (num >= 1000) {
//         a = Math.floor(num / 1000)
//         b = Math.floor((num % 1000) / 100)
//         //c = Math.floor(num % 100 / 10);
//         sysbol = 'k'
//       }

//       if (a > 99) {
//         str = a.toString()
//       } else if (b > 0) {
//         str = `${a}.${b}`
//       } else {
//         str = a.toString()
//       }
//     }
//     return str + sysbol
//   }

//   /**
//    * 数字转成字符串
//    * @param num
//    */
//   public numberToString4(num: number) {
//     let str = ''
//     let sysbol = ''
//     if (num < 10000) {
//       str = num.toString()
//     } else {
//       let a = 0
//       let b = 0
//       let c = 0
//       if (num >= 1000000) {
//         a = Math.floor(num / 1000000)
//         b = Math.floor((num % 1000000) / 100000)
//         c = Math.floor((num % 100000) / 10000)
//         sysbol = 'm'
//       } else if (num >= 10000) {
//         a = Math.floor(num / 1000)
//         b = Math.floor((num % 1000) / 100)
//         c = Math.floor((num % 100) / 10)
//         sysbol = 'k'
//       }

//       if (a > 99) {
//         str = a.toString()
//       } else if (a > 9) {
//         if (b == 0) {
//           str = a.toString()
//         } else {
//           str = `${a}.${b}`
//         }
//       } else if (c == 0) {
//         if (b == 0) {
//           str = a.toString()
//         } else {
//           str = `${a}.${b}`
//         }
//       } else {
//         str = `${a}.${b}${c}`
//       }
//     }
//     return str + sysbol
//   }

//   /**
//    * 数字转化为进制字符串，支持正负数
//    * 当伤害数字达到6位数时，将伤害数字/1000，并且取1位小数，后缀加上字母k
//    * 当伤害数字达到8位数时，将伤害数字/1000000，并且取1位小数，后缀加上字母m
//    *  */
//   public numberToString5(num: number) {
//     /** 正负号 */
//     const symbol = num >= 0 ? '' : '-'
//     num = Math.abs(Math.floor(num))
//     let str = ''
//     let sysbol = ''
//     if (num < 100000) {
//       str = num.toString()
//     } else {
//       let a = 0
//       let b = 0
//       if (num >= 10000000) {
//         a = Math.floor(num / 1000000)
//         b = Math.floor((num % 1000000) / 100000)
//         sysbol = 'm'
//       } else if (num >= 100000) {
//         a = Math.floor(num / 1000)
//         b = Math.floor((num % 1000) / 100)
//         sysbol = 'k'
//       }

//       if (b > 0) {
//         str = `${a}.${b}`
//       } else {
//         str = a.toString()
//       }
//     }
//     return symbol + str + sysbol
//   }

//   /**
//    * 数字转成字符串
//    * @param num
//    */
//   public numberToString(num: number) {
//     let str = ''
//     let sysbol = ''
//     if (num < 1000) {
//       str = num.toString()
//     } else {
//       let a = 0
//       let b = 0
//       let c = 0
//       if (num >= 1000000) {
//         a = Math.floor(num / 1000000)
//         b = Math.floor((num % 1000000) / 100000)
//         c = Math.floor((num % 100000) / 10000)
//         sysbol = 'm'
//       } else if (num >= 1000) {
//         a = Math.floor(num / 1000)
//         b = Math.floor((num % 1000) / 100)
//         c = Math.floor((num % 100) / 10)
//         sysbol = 'k'
//       }

//       if (a > 99) {
//         str = a.toString()
//       } else if (a > 9) {
//         if (b == 0) {
//           str = a.toString()
//         } else {
//           str = `${a}.${b}`
//         }
//       } else if (c == 0) {
//         if (b == 0) {
//           str = a.toString()
//         } else {
//           str = `${a}.${b}`
//         }
//       } else {
//         str = `${a}.${b}${c}`
//       }
//     }
//     return str + sysbol
//   }

//   /**
//    * 日期字符串转为毫秒
//    */
//   public getTimeFromStringDate(dateStr: string, timeZone = 8): number {
//     const offset_GMT = new Date().getTimezoneOffset() // 本地时间和格林威治的时间差，单位为分钟
//     const nowDate = new Date(DYTools.transformDate(dateStr)).getTime() // 时间距 1970 年 1 月 1 日午夜（GMT 时间）之间的毫秒数
//     const targetDate = new Date(nowDate - (offset_GMT * 60 * 1000 + timeZone * 60 * 60 * 1000))
//     return targetDate.getTime()
//   }

//   /**
//    * 根据秒获取 时分秒数组
//    * @param sec 秒
//    */
//   public getTime(sec: number): number[] {
//     const ret = []
//     const hour = Math.floor(sec / 3600)
//     const min = Math.floor((sec - hour * 3600) / 60)
//     const seco = Math.floor(sec % 60)
//     ret.push(hour)
//     ret.push(min)
//     ret.push(seco)
//     return ret
//   }

//   /**
//    * 获取时间字符串
//    * @param num 秒
//    * @return 分:秒
//    */
//   public getTimeStrForMS(num: number): string {
//     let time = '00:00'
//     if (num < 60) {
//       time = `00:${this.getTimeStrDouble(num)}`
//     } else if (num < 3600) {
//       const m = Math.floor(num / 60)
//       const s = Math.floor(num % 60)
//       time = `${this.getTimeStrDouble(m)}:${this.getTimeStrDouble(s)}`
//     } else {
//       // if (num < 3600 * 60)
//       const h = Math.floor(num / 3600)
//       const ms = Math.floor(num % 3600)
//       const m = Math.floor(ms / 60)
//       const s = Math.floor(ms % 60)
//       time = `${this.getTimeStrDouble(h)}:${this.getTimeStrDouble(m)}:${this.getTimeStrDouble(s)}`
//     }
//     return time
//   }

//   /**
//    * 获取时间字符串
//    * @param num 秒
//    * @return 时:分:秒
//    */
//   public getTimeStrForHMS(num: number): string {
//     let time = '00:00:00'
//     if (num < 60) {
//       time = `00:00:${this.getTimeStrDouble(num)}`
//     } else if (num < 3600) {
//       const m = Math.floor(num / 60)
//       const s = Math.floor(num % 60)
//       time = `00:${this.getTimeStrDouble(m)}:${this.getTimeStrDouble(s)}`
//     } else {
//       // if (num < 3600 * 60)
//       const h = Math.floor(num / 3600)
//       const ms = Math.floor(num % 3600)
//       const m = Math.floor(ms / 60)
//       const s = Math.floor(ms % 60)
//       time = `${this.getTimeStrDouble(h)}:${this.getTimeStrDouble(m)}:${this.getTimeStrDouble(s)}`
//     }
//     return time
//   }

//   public getTimeStrForHMS1(num: number): string {
//     let time = ''
//     if (num < 60) {
//       time = `${num}秒`
//     } else if (num < 3600) {
//       const m = Math.floor(num / 60)
//       const s = Math.floor(num % 60)
//       time = `${m}分${s}秒`
//     } else if (num < 3600 * 24) {
//       const h = Math.floor(num / 3600)
//       const ms = Math.floor(num % 3600)
//       const m = Math.floor(ms / 60)
//       const s = Math.floor(ms % 60)
//       time = `${h}小时${m}分${s}秒`
//     } else {
//       const d = Math.floor(num / 86400)
//       const hs = Math.floor(num % 86400)
//       const h = Math.floor(hs / 3600)
//       const ms = Math.floor(hs % 3600)
//       const m = Math.floor(ms / 60)
//       const s = Math.floor(ms % 60)
//       time = `${d}天${h}小时${m}分` // + s + "秒";
//     }
//     return time
//   }

//   /**
//    * 根据时间戳获取年月日
//    * @param time
//    * @returns
//    */
//   public getTimeStrForYMD(time: string | number): string {
//     let timeStr = ''
//     const date = new Date(time)
//     const year = date.getFullYear()
//     const month = date.getMonth() + 1 < 10 ? `0${date.getMonth() + 1}` : date.getMonth() + 1
//     const curDate = date.getDate() < 10 ? `0${date.getDate()}` : date.getDate()
//     timeStr = `${year}-${month}-${curDate}`
//     return timeStr
//   }

//   /**
//    * 把一个 日期类型 转换为  yyyy/MM/dd HH:mm:ss 格式
//    * @param time
//    */
//   public getTimeStrByDate(time: Date | number): string {
//     const isNumber = typeof time === 'number'
//     let date: Date
//     if (isNumber) {
//       date = new Date(time)
//     } else {
//       date = time
//     }
//     const year = date.getFullYear()
//     const month = String(date.getMonth() + 1).padStart(2, '0')
//     const day = String(date.getDate()).padStart(2, '0')
//     const hours = String(date.getHours()).padStart(2, '0')
//     const minutes = String(date.getMinutes()).padStart(2, '0')
//     const seconds = String(date.getSeconds()).padStart(2, '0')
//     return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`
//   }

//   public getTimeStrForDH(num: number | string): string {
//     let timeStr = ''
//     num = Number(num) / 1000
//     if (num < 3600) {
//       timeStr = `1 ${LanguageMgr.getTxt(TextId.Hour)}`
//     } else if (num < 3600 * 24) {
//       const h = Math.ceil(num / 3600)
//       timeStr = `${h} ${LanguageMgr.getTxt(TextId.Hour)}`
//     } else {
//       const d = Math.ceil(num / (3600 * 24))
//       timeStr = `${d} ${LanguageMgr.getTxt(TextId.Day)}`
//     }
//     return timeStr
//   }

//   /**
//    * 获取时间字符串
//    * @param num 秒
//    * @return （天 小时） 或 （时:分:秒）
//    */
//   public getTimeStrForDHMS(num: number): string {
//     const dayNum: number = 3600 * 24
//     let time = '00:00:00'
//     if (num < 60) {
//       time = `00:00:${this.getTimeStrDouble(num)}`
//     } else if (num < 3600) {
//       const m = Math.floor(num / 60)
//       const s = Math.floor(num % 60)
//       time = `00:${this.getTimeStrDouble(m)}:${this.getTimeStrDouble(s)}`
//     } else if (num < dayNum) {
//       const h = Math.floor(num / 3600)
//       const ms = Math.floor(num % 3600)
//       const m = Math.floor(ms / 60)
//       const s = Math.floor(ms % 60)
//       time = `${this.getTimeStrDouble(h)}:${this.getTimeStrDouble(m)}:${this.getTimeStrDouble(s)}`
//     } else {
//       const d = Math.floor(num / dayNum)
//       const mh = Math.floor(num % dayNum)
//       const h = Math.floor(mh / 3600)
//       const ms = Math.floor(mh % 3600)
//       const m = Math.floor(ms / 60)
//       const s = Math.floor(ms % 60)
//       //time = d + " " + LanguageMgr.getTxt(TextId.Day) + " " + this.getTimeStrDouble(h) + ":" + this.getTimeStrDouble(m) + ":" + this.getTimeStrDouble(s);
//       if (h > 0) {
//         time = LanguageMgr.getTxt(TextId.DayHour, d, h)
//       } else {
//         time = d + LanguageMgr.getTxt(TextId.Day)
//       }
//     }
//     return time
//   }

//   /**
//    * 获取时间字符串
//    * @param num 秒
//    * @return （天 小时） 或 （时:分:秒）
//    */
//   public getTimeStrForMainDHMS(num: number): string {
//     const dayNum: number = 3600 * 24
//     let time = '00:00:00'
//     if (num < 60) {
//       time = `00:00:${this.getTimeStrDouble(num)}`
//     } else if (num < 3600) {
//       const m = Math.floor(num / 60)
//       const s = Math.floor(num % 60)
//       time = `00:${this.getTimeStrDouble(m)}:${this.getTimeStrDouble(s)}`
//     } else if (num < dayNum) {
//       const h = Math.floor(num / 3600)
//       const ms = Math.floor(num % 3600)
//       const m = Math.floor(ms / 60)
//       const s = Math.floor(ms % 60)
//       time = `${this.getTimeStrDouble(h)}:${this.getTimeStrDouble(m)}:${this.getTimeStrDouble(s)}`
//     } else {
//       const d = Math.floor(num / dayNum)
//       const mh = Math.floor(num % dayNum)
//       const h = Math.ceil(mh / 3600)
//       // const ms = Math.floor(mh % 3600);
//       // const m = Math.floor(ms / 60);
//       // const s = Math.floor(ms % 60);
//       //time = d + " " + LanguageMgr.getTxt(TextId.Day) + " " + this.getTimeStrDouble(h) + ":" + this.getTimeStrDouble(m) + ":" + this.getTimeStrDouble(s);
//       time = LanguageMgr.getTxt(TextId.DayHour, d, h)
//     }
//     return time
//   }

//   /**
//    * 获取时间字符串（sfm）
//    * @param num
//    * @returns 时h分f秒m
//    */
//   public getTimeStrForSFM(num: number): string {
//     num = Math.ceil(num)
//     let time = ''
//     if (num < 60) {
//       time = `${num}m`
//     } else if (num < 3600) {
//       const m = Math.floor(num / 60)
//       const s = Math.floor(num % 60)
//       time = `${m}f`
//       if (s > 0) {
//         time = `${time + s}m`
//       }
//     } else if (num < 3600 * 24) {
//       const h = Math.floor(num / 3600)
//       const ms = Math.floor(num % 3600)
//       const m = Math.floor(ms / 60)
//       const s = Math.floor(ms % 60)
//       time = `${h}s`
//       if (m > 0) {
//         time = `${time + m}f`
//       }
//       if (s > 0) {
//         time = `${time + s}m`
//       }
//     }
//     return time
//   }

//   /**
//    * 获取时间字符串（ms）
//    * @param num
//    * @returns 分m秒s
//    */
//   public getTimeStrForSFM1(num: number): string {
//     num = Math.ceil(num)
//     let time = ''
//     if (num < 60) {
//       time = `${num}s`
//     } else {
//       const m = Math.floor(num / 60)
//       const s = Math.floor(num % 60)
//       time = `${m}m`
//       if (s > 0) {
//         time = `${time + s}s`
//       }
//     }
//     return time
//   }

//   /**
//    * 获取时间字符串最多2个（sfm）
//    * @param num
//    * @returns 时h分f秒m
//    */
//   public getTimeStrForSFM2(num: number) {
//     num = Math.ceil(num)
//     let time = ''
//     if (num < 60) {
//       time = `${num}m`
//     } else if (num < 3600) {
//       const m = Math.floor(num / 60)
//       const s = Math.floor(num % 60)
//       time = `${m}f`
//       if (s > 0) {
//         time = `${time + s}m`
//       }
//     } else if (num < 3600 * 24) {
//       const h = Math.floor(num / 3600)
//       const ms = Math.floor(num % 3600)
//       const m = Math.floor(ms / 60)
//       const s = Math.floor(ms % 60)
//       time = `${h}s`
//       if (m > 0) {
//         time = `${time + m}f`
//       }
//     }
//     return time
//   }

//   /**
//     /**
//      * 获取时间字符串（天day,小时hour,分minute,秒second,前两位)
//      * @param num
//      */
//   public getTimeStrForDSFM2(num: number) {
//     num = Math.ceil(num)
//     let time = ''
//     if (num < 3600) {
//       const m = Math.floor(num / 60)
//       const s = Math.floor(num % 60)
//       time = `${m}m ${s}s`
//     } else if (num < 3600 * 24) {
//       const h = Math.floor(num / 3600)
//       const ms = Math.floor(num % 3600)
//       const m = Math.floor(ms / 60)
//       time = `${h}h ${m}m`
//     } else {
//       const d = Math.floor(num / (3600 * 24))
//       const temp = Math.floor(num % (3600 * 24))
//       const h = Math.ceil(temp / 3600) //Math.floor(temp/3600);
//       time = `${d}d ${h}h`
//     }
//     return time
//   }

//   /** 获取时间：yyyy-mm-dd hh:mm:ss */
//   public getTimeStr1(timestamp: number) {
//     timestamp = timestamp ?? DYTools.getCurTimestamp()
//     const date = new Date(timestamp)
//     const year = date.getFullYear()
//     const month = date.getMonth() + 1
//     const day = date.getDate()
//     const hour = date.getHours()
//     const minute = date.getMinutes()
//     const second = date.getSeconds()

//     const date1 = `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`
//     const date2 = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:${second
//       .toString()
//       .padStart(2, '0')}`
//     const str = `${date1} ${date2}`
//     return str
//   }

//   /**
//    * 获取时间：hh:mm:ss
//    * @param timestamp ms
//    * @returns hh:mm:ss
//    */
//   public getTimeStr2(timestamp: number) {
//     timestamp = timestamp ?? DYTools.getCurTimestamp()
//     const date = new Date(timestamp)
//     const hour = date.getHours()
//     const minute = date.getMinutes()
//     const second = date.getSeconds()
//     const date2 = `${hour.toString().padStart(2, '0')}: ${minute.toString().padStart(2, '0')}: ${second
//       .toString()
//       .padStart(2, '0')}`
//     const str = `${date2}`
//     return str
//   }

//   /*
//    * 功能：十位补0
//    */
//   private getTimeStrDouble(num: number): string {
//     let time = '00'
//     num = parseInt(num.toFixed(0))
//     if (num < 10) {
//       time = `0${num}`
//     } else if (num < 60) {
//       time = `${num}`
//     } else {
//       time = `${num}`
//     }

//     return time
//   }

//   /********************** 数组操作 *********************/
//   /**
//    * 数组移除
//    * @param arr
//    * @param removeItem
//    */
//   public arrRemove(arr: any[], removeItem: any) {
//     if (!isValid(arr)) {
//       return false
//     }
//     for (let i = 0; i < arr.length; i++) {
//       if (arr[i] == removeItem) {
//         arr.splice(i, 1)
//         return true
//       }
//     }
//     return false
//   }

//   /**
//    * 数组移除数组
//    * @param arr
//    * @param removeItemArr
//    */
//   public arrRemoveArr(arr: any[], removeItemArr: any[]) {
//     if (!isValid(arr)) {
//       return false
//     }
//     for (let i = 0; i < arr.length; i++) {
//       if (this.arrContain(removeItemArr, arr[i])) {
//         arr.splice(i, 1)
//         return true
//       }
//     }
//     return false
//   }

//   /**
//    * 数组包含
//    * @param arr
//    * @param item
//    * @param property 属性
//    */
//   public arrContain(arr: any[], item: any, property: string = undefined) {
//     if (arr && item != undefined && item != null) {
//       if (property) {
//         for (let i = 0; i < arr.length; i++) {
//           if (arr[i].hasOwnProperty(property) && arr[i][property] == item) {
//             return true
//           }
//         }
//       } else {
//         const index = arr.indexOf(item)
//         return index >= 0
//       }
//     }
//     return false
//   }

//   /**
//    * 数组添加
//    * @param arr
//    * @param item
//    * @returns
//    */
//   public arrAdd(arr: any[], item: any) {
//     if (arr && item !== undefined && item !== null) {
//       if (!DYTools.arrContain(arr, item)) {
//         arr.push(item)
//         return true
//       }
//     }
//     return false
//   }

//   /**
//    * vec2包含
//    */
//   public arrContainPos(arr: Vec2[], pos: Vec2) {
//     for (let index = 0; index < arr.length; index++) {
//       const item: Vec2 = arr[index]
//       if (item.equals(pos)) {
//         return true
//       }
//     }

//     return false
//   }

//   /**
//    * 数组移动，右为正
//    * @param arr
//    * @param move
//    * @param copy
//    */
//   public arrMove(arr: any[], move: number, copy = false) {
//     if (copy) {
//       arr = this.copyArray(arr)
//     }
//     const len = arr.length
//     move %= len
//     if (move < 0) {
//       move = len - Math.abs(move)
//     }
//     arr = this.reverse(arr, 0, len - move - 1)
//     arr = this.reverse(arr, len - move, len - 1)
//     arr = this.reverse(arr, 0, len - 1)
//     return arr
//   }

//   /**
//    * 数组反转
//    * @param arr
//    * @param i
//    * @param j
//    */
//   public reverse(arr: any[], i: number, j: number) {
//     for (; i < j; i++, j--) {
//       const tmp = arr[i]
//       arr[i] = arr[j]
//       arr[j] = tmp
//     }
//     return arr
//   }

//   /**
//    * 从数组中随机获取一个元素
//    * @param arr 源数组
//    * @param remove 是否从源数组删除获取到的元素
//    */
//   public getRandomInArray<T>(arr: T[], remove = false): T {
//     const len = arr.length
//     const ran = len > 0 ? this.random_int(0, len - 1) : -1

//     if (ran >= 0) {
//       const ret = arr[ran]
//       if (remove) {
//         arr.splice(ran, 1)
//       }
//       return ret
//     }

//     return null
//   }

//   /**
//    * 数组里面随机一定数量元素
//    * @param param arr:源数组;count:获取数量;repeat:是否允许重复元素;remove:是否从源数组中删除获得的元素
//    * @returns
//    */
//   public getRandomCountInArray(param: {
//     arr: any[]
//     count: number
//     ignore?: any[]
//     repeat?: boolean
//     remove?: boolean
//   }) {
//     const ret = []
//     const temp = this.copyArray(param.arr, param.ignore) //param.repeat ? param.arr :
//     for (let i = 0; i < param.count; i++) {
//       const len = temp.length
//       const ran = len > 0 ? this.random_int(0, len - 1) : -1
//       if (ran >= 0) {
//         ret.push(temp[ran])
//         if (!param.repeat) {
//           temp.splice(ran, 1)
//         }
//       } else {
//         break
//       }
//     }

//     if (param.remove) {
//       for (const item of ret) {
//         this.arrRemove(param.arr, item)
//       }
//     }

//     return ret
//   }

//   /**
//    * 深拷贝数组（不深拷贝元素）
//    * @param arr 源数组
//    */
//   public copyArray(arr: any[], ignore?: any[]) {
//     const ret = []
//     if (arr) {
//       for (const item of arr) {
//         if (ignore && ignore.indexOf(item) >= 0) {
//           continue
//         }
//         ret.push(item)
//       }
//     }
//     return ret
//   }

//   public copyDict(dict: { [key: number]: number }) {
//     const ret: { [key: number]: number } = {}
//     if (dict) {
//       for (const key in dict) {
//         ret[parseInt(key)] = dict[key]
//       }
//     }
//     return ret
//   }

//   /**
//    * 数组插入
//    * @param arr 源数组
//    * @param index 插入索引
//    * @param item 插入元素
//    */
//   public arrayInsert(arr: any[], index: number, item: any): any[] {
//     const { length } = arr
//     if (length > index) {
//       const tmpArr = arr.splice(index, arr.length)
//       arr.push(item)
//       arr = arr.concat(tmpArr)
//     } else {
//       arr.push(item)
//     }
//     return arr
//   }

//   /**
//    * 数组随机位置插入元素
//    * @param arr 源数组
//    * @param item 要插入的元素
//    */
//   public arrayInsertRandom(arr: any[], item: any): any[] {
//     let index = -1
//     const { length } = arr

//     if (length > 0) {
//       index = DYTools.random_int(0, length)
//     }

//     if (index >= 0 && length > index) {
//       const tmpArr = arr.splice(index, length)
//       arr.push(item)
//       arr = arr.concat(tmpArr)
//     } else {
//       arr.push(item)
//     }
//     return arr
//   }

//   /**************** cocos *****************/
//   /**
//    * 组件添加
//    * @param node
//    * @param comp
//    */
//   public addScript(node, comp) {
//     if (node && comp) {
//       let ret = node.getComponent(comp)
//       if (!ret) {
//         ret = node.addComponent(comp)
//       }
//       return ret
//     }
//     return null
//   }

//   /** 坐标转换 */
//   public getPositionForParent(parent: Node, child: Node) {
//     if (parent && child) {
//       const worldPos = child.convertToWorldSpaceAR(Vec2.ZERO)
//       const pos = parent.convertToNodeSpaceAR(worldPos)
//       return pos
//     }
//     return Vec2.ZERO
//   }

//   /**
//    * 移除子结点
//    * @param parent
//    * @param name
//    */
//   public removeChildByName(parent: Node, name: string) {
//     if (parent) {
//       const child = parent.getChildByName(name)
//       if (child) {
//         child.destroy()
//       }
//     }
//   }

//   /** 数组结点删除 */
//   public clearArrayForComp(arr: Component[]) {
//     if (isValid(arr)) {
//       arr.forEach(value => {
//         if (value && value.node) {
//           if (isValid(value) && isValid(value.node)) {
//             value.node.destroy()
//           }
//         }
//       })
//       arr.splice(0)
//     }
//   }

//   public clearArrayForNode(arr: Node[]) {
//     if (isValid(arr)) {
//       arr.forEach(value => {
//         if (isValid(value)) {
//           value.destroy()
//         }
//       })
//       arr.splice(0)
//     }
//   }

//   /** map结点删除 */
//   public clearMapForNode(map: Map<any, Node>) {
//     if (map) {
//       map.forEach((value, key) => {
//         if (value && isValid(value)) {
//           value.destroy()
//         }
//       })
//       map.clear()
//     }
//   }

//   public clearMapForNodeArr(map: Map<any, Node[]>) {
//     if (map) {
//       map.forEach((value, key) => {
//         value.forEach(node => {
//           if (isValid(node)) {
//             node.destroy()
//           }
//         })
//       })
//       map.clear()
//     }
//   }

//   public clearMapForComp(map: Map<any, Component>) {
//     if (map) {
//       map.forEach((value, key) => {
//         if (value && value.node) {
//           if (isValid(value.node)) {
//             value.node.destroy()
//           }
//         }
//       })
//       map.clear()
//     }
//   }

//   public clearMapForCompArr(map: Map<any, Component[]>) {
//     if (map) {
//       map.forEach((value, key) => {
//         value.forEach(comp => {
//           if (comp && comp.node) {
//             if (isValid(comp.node)) {
//               comp.node.destroy()
//             }
//           }
//         })
//       })
//       map.clear()
//     }
//   }

//   /** 清理pool */
//   public clearNodePool(pool: NodePool) {
//     if (pool) {
//       while (pool.size() > 0) {
//         const node = pool.get()
//         if (node && isValid(node)) {
//           node.destroy()
//         }
//       }
//       pool.clear()
//     }
//   }

//   /** 将节点的父节点置空，避免visitNode消耗过高 */
//   public setNodesParentNull(nodes: Node[]) {
//     this.clearArrayForNode(nodes)
//     return

//     if (nodes?.length > 0) {
//       for (let i = 0; i < nodes.length; i++) {
//         if (isValid(nodes[i])) nodes[i].parent = null
//       }
//     }
//   }

//   public setCompNodeArrayParentNull(comps: Component[]) {
//     this.clearArrayForComp(comps)
//     return

//     if (comps?.length > 0) {
//       for (let i = 0; i < comps.length; i++) {
//         if (isValid(comps[i].node)) comps[i].node.parent = null
//       }
//       comps.splice(0)
//     }
//   }

//   public setCompNodeDictParentNull(dict: { [key: number]: Component[] }) {
//     if (dict) {
//       for (const key in dict) {
//         this.setCompNodeArrayParentNull(dict[key])
//       }
//     }
//   }

//   /** 递归计算子孙节点总数量 */
//   public getChildrenCount(node: Node): number {
//     let { childrenCount } = node
//     for (let i = 0; i < node.children.length; i++) {
//       const child = node.children[i]
//       childrenCount += this.getChildrenCount(child)
//     }
//     return childrenCount
//   }

//   /** 以名字为key，统计子节点的个数和孙节点个数 */
//   public getChildrenNodeCountDetails(parent: Node): {
//     [key: string]: { count: number; nodeCount: number; name: string }
//   } {
//     const dict = {}
//     for (let i = 0; i < parent.children.length; i++) {
//       const child = parent.children[i]
//       const nodeCount = this.getChildrenCount(child) + 1
//       if (!dict[child.name]) {
//         dict[child.name] = {
//           name: child.name,
//           count: 1,
//           nodeCount,
//         }
//       } else {
//         const obj = dict[child.name]
//         obj.count++
//         obj.nodeCount += nodeCount
//       }
//     }
//     return dict
//   }

//   public sortChildrenNodeCountDetails(details: {
//     [key: string]: { count: number; nodeCount: number }
//   }): { count: number; nodeCount: number }[] {
//     const array = []
//     for (const key in details) {
//       array.push(details[key])
//     }
//     array.sort((a, b) => b.nodeCount - a.nodeCount)
//     return array
//   }

//   /****************** 向量-角度 *****************/
//   /**
//    * 获取直线与cc.v2(0, -1)夹角（角度）
//    * @param startX
//    * @param startY
//    * @param endX
//    * @param endY
//    */
//   public getLineDegrees(startX: number, startY: number, endX: number, endY: number) {
//     const dir = v2(endX, endY).sub(v2(startX, startY))
//     const comVec = v2(0, -1) // 向下的对比向量
//     const radian = this.getSignAngle(dir, comVec) // 求方向向量与对比向量间的弧度
//     const degrees = misc.radiansToDegrees(radian)

//     return degrees
//   }

//   /**
//    * 获取向量与cc.v2(0, -1)的夹角（角度）
//    * @param dir
//    */
//   public getDegreeForDir(dir: Vec2) {
//     let degrees = 0
//     const comVec = v2(0, -1) // 向下的对比向量
//     if (dir.equals(comVec) || dir.equals(Vec2.ZERO)) {
//       return degrees
//     }
//     const radian = this.getSignAngle(dir, comVec) // 求方向向量与对比向量间的弧度
//     degrees = misc.radiansToDegrees(radian)

//     return degrees
//   }

//   /**
//    * 获取直线单位向量
//    * @param startX
//    * @param startY
//    * @param endX
//    * @param endY
//    */
//   public getDir(startX: number, startY: number, endX: number, endY: number) {
//     return v2(endX, endY).sub(v2(startX, startY)).normalize()
//   }

//   /** 根据向量获取角度(0~360) */
//   public getVecDegree(vec: Vec2) {
//     const d = Math.sqrt(vec.x * vec.x + vec.y * vec.y)

//     if (d == 0) {
//       return 0
//     }
//     let angle: number = misc.radiansToDegrees(Math.asin(vec.x / d))
//     if (vec.y < 0) {
//       angle = 180 - angle
//     }
//     angle = -angle
//     if (angle > 360) {
//       angle -= 360
//     } else if (angle < 0) {
//       angle += 360
//     }
//     return angle
//   }

//   /** 获取角度(-180~180) */
//   public getAngle(start: Vec2 | Vec3, end: Vec2 | Vec3) {
//     const dx = end.x - start.x
//     const dy = end.y - start.y
//     const d = Math.sqrt(dx * dx + dy * dy)

//     if (d == 0) {
//       return 0
//     }
//     let angle: number = misc.radiansToDegrees(Math.asin(dx / d))
//     if (dy < 0) {
//       angle = 180 - angle
//     }
//     angle = -angle
//     if (angle > 180) {
//       angle -= 360
//     } else if (angle < -180) {
//       angle += 360
//     }
//     return angle
//   }

//   public getPositionByAngle(pos: { x: number; y: number }, angle: number): { x: number; y: number } {
//     const lenght = Math.sqrt(pos.x * pos.x + pos.y * pos.y)
//     const beginAng = (Math.atan2(pos.y, pos.x) / Math.PI) * 180
//     const nowAng = ((beginAng + angle) / 180) * Math.PI
//     const x = Math.cos(nowAng) * lenght
//     const y = Math.sin(nowAng) * lenght
//     return { x, y }
//   }

//   /**
//    * 角度转成0-360
//    * @param degree
//    */
//   public getResetDegree(degree: number) {
//     if (degree > 0) {
//       const tmp = Math.floor(degree / 360)
//       degree -= tmp * 360
//     } else if (degree < 0) {
//       const tmp = Math.ceil(Math.abs(degree / 360))
//       degree += tmp * 360
//     }
//     return degree
//   }

//   /**
//    * 角度转成  -180-180
//    * @param degree
//    */
//   public getSingedResetAngle(degree: number) {
//     if (degree > 180) {
//       const tmp = Math.ceil(degree / 360)
//       degree -= tmp * 360
//     } else if (degree < -180) {
//       const tmp = Math.ceil(Math.abs(degree / 360))
//       degree += tmp * 360
//     }
//     return degree
//   }

//   private m_cachedVec01: Vec2 = Vec2.ZERO

//   private m_cachedVec02: Vec2 = Vec2.ZERO

//   /** 旋转至目标 */
//   public rotateToTarget(
//     dt: number,
//     rotateSpeed: number,
//     currentAngle: number,
//     currentPos: Vec2,
//     targetPos: Vec2,
//   ): {
//     finish: boolean
//     angle: number
//   } {
//     // 当前点位置
//     const curPos: Vec2 = currentPos
//     // 当前角度
//     let curAngle: number = currentAngle
//     // 使用缓存向量计算
//     this.m_cachedVec01.x = targetPos.x
//     this.m_cachedVec01.y = targetPos.y
//     this.m_cachedVec02.x = 0
//     this.m_cachedVec02.y = 1
//     this.m_cachedVec01.subSelf(curPos)
//     const dir: Vec2 = this.m_cachedVec01.normalizeSelf()
//     const up: Vec2 = this.m_cachedVec02
//     let targetAngle: number = -misc.radiansToDegrees(DYTools.getSignAngle(dir, up))
//     let isAdd = false
//     let isEqual = false
//     if (targetAngle > curAngle) {
//       while (targetAngle - curAngle >= 360) {
//         targetAngle -= 360
//       }
//     } else if (targetAngle < curAngle) {
//       while (curAngle - targetAngle >= 360) {
//         targetAngle += 360
//       }
//     }

//     if (targetAngle > curAngle) {
//       if (targetAngle - curAngle <= 180) {
//         isAdd = true
//       } else {
//         targetAngle -= 360
//       }
//     } else if (targetAngle < curAngle) {
//       if (curAngle - targetAngle > 180) {
//         targetAngle += 360
//         isAdd = true
//       }
//     } else {
//       // 角度相等
//       isEqual = true
//     }

//     let isFinish = false
//     if (!isEqual) {
//       if (isAdd) {
//         let newAngle: number = curAngle + rotateSpeed * dt
//         if (newAngle > targetAngle) {
//           newAngle = targetAngle
//           isFinish = true
//         }
//         curAngle = newAngle
//       } else {
//         let newAngle: number = curAngle - rotateSpeed * dt
//         if (newAngle < targetAngle) {
//           newAngle = targetAngle
//           isFinish = true
//         }
//         curAngle = newAngle
//       }
//     }

//     // 结果
//     return {
//       finish: isFinish || isEqual,
//       angle: curAngle,
//     }
//   }

//   /** 追踪目标 */
//   public chaseTarget(
//     dt: number,
//     speed: number,
//     currentPos: Vec2,
//     targetPos: Vec2,
//     out?: Vec2,
//   ): {
//     finish: boolean
//     pos: Vec2
//   } {
//     //当前位置
//     const curPos = currentPos
//     const target = out ? out : v2(0, 0)
//     //剩余距离
//     const distance = Vec2.distance(targetPos, curPos)
//     const moveLen = speed * dt
//     let isReach = false
//     if (moveLen >= distance) {
//       isReach = true
//       target.x = currentPos.x
//       target.y = currentPos.y
//     } else {
//       targetPos.sub(curPos, this.m_cachedVec01)
//       this.m_cachedVec01.normalizeSelf()
//       this.m_cachedVec01.mulSelf(moveLen)
//       target.x = curPos.x + this.m_cachedVec01.x
//       target.y = curPos.y + this.m_cachedVec01.y
//     }
//     // 结果
//     return {
//       finish: isReach,
//       pos: target,
//     }
//   }

//   /**
//    * 求线性插值系数
//    * 同Unity的Mathf.InverseLerp：Calculates the linear parameter t that produces the interpolant value within the range [a, b].
//    */
//   public inverseLerp(a: number, b: number, v: number): number {
//     return (v - a) / (v - b)
//   }

//   // 生成随机id
//   private charArr = [
//     '0',
//     '1',
//     '2',
//     '3',
//     '4',
//     '5',
//     '6',
//     '7',
//     '8',
//     '9',
//     'a',
//     'b',
//     'c',
//     'd',
//     'e',
//     'f',
//     'g',
//     'h',
//     'i',
//     'j',
//     'k',
//     'l',
//     'm',
//     'n',
//     'o',
//     'p',
//     'q',
//     'r',
//     's',
//     't',
//     'u',
//     'v',
//     'w',
//     'x',
//     'y',
//     'z',
//     'A',
//     'B',
//     'C',
//     'D',
//     'E',
//     'F',
//     'G',
//     'H',
//     'I',
//     'J',
//     'K',
//     'L',
//     'M',
//     'N',
//     'O',
//     'P',
//     'Q',
//     'R',
//     'S',
//     'T',
//     'U',
//     'V',
//     'W',
//     'X',
//     'Y',
//     'Z',
//   ]

//   public getRandomUserId() {
//     const count = 32
//     const length = this.charArr.length - 1
//     let str = ''
//     for (let i = 0; i < count; i++) {
//       const random = this.random_int(0, length)
//       str += this.charArr[random]
//     }

//     return str
//   }

//   public getRandomAdId() {
//     const count = 64
//     const length = this.charArr.length - 1
//     let str = ''
//     for (let i = 0; i < count; i++) {
//       const random = this.random_int(0, length)
//       str += this.charArr[random]
//     }

//     return str
//   }

//   /********** 碰撞检测 **********/
//   /** 圆形和圆形碰撞 */
//   public checkCircleCircle(cp0: Vec2, radius0: number, cp1: Vec2, radius1: number) {
//     const dif = cp0.sub(cp1, this.cachedVec2)
//     const dis = radius0 + radius1
//     if (Math.abs(dif.x) > dis || Math.abs(dif.y) > dis) {
//       return false
//     }
//     if (dif.magSqr() <= dis * dis) {
//       return true
//     }
//     return false
//   }

//   /** 矩形和圆形碰撞 */
//   public checkCircleRect(cp: Vec2, radius: number, rp: Vec2, size: Size) {
//     return Math.abs(rp.x - cp.x) <= size.width / 2 + radius && Math.abs(rp.y - cp.y) <= size.height / 2 + radius
//   }

//   /** 矩形和矩形碰撞 */
//   public checkRectRect(rp0: Vec2, size0: Size, rp1: Vec2, size1: Size) {
//     const difX = Math.abs(rp0.x - rp1.x)
//     const difY = Math.abs(rp0.y - rp1.y)
//     const width = (size0.width + size1.width) / 2
//     const height = (size0.height + size1.height) / 2
//     return difX <= width && difY <= height
//   }

//   /** 有角度矩形和圆形碰撞 */
//   public checkCircleRotateRect(cp: Vec2, radius: number, rp: Vec2, size: Size, angle: number) {
//     //TODO::方法不够准确需改进
//     const an = this.getAngle(rp, cp)
//     const adjustAngle = an - angle
//     const dis = Math.sqrt(Math.abs(cp.x - rp.x) * Math.abs(cp.x - rp.x) + Math.abs(cp.y - rp.y) * Math.abs(cp.y - rp.y))
//     //let verticPos = this.getPositionByAngle(pos, adjustAngle);
//     const x = -Math.sin((adjustAngle / 180) * Math.PI) * dis
//     const y = Math.cos((adjustAngle / 180) * Math.PI) * dis
//     return Math.abs(x) <= size.width / 2 + radius && Math.abs(y) <= size.height / 2 + radius
//   }

//   /***
//    * 检测点是否在正方形区域中
//    * @param areaPos 区域中心位置
//    * @param radius 区域半径
//    * @param pos 点位置
//    */
//   public checkPointInArea(areaPos: Vec3, pos: Vec3, radius: number) {
//     const diff = pos.sub(areaPos)
//     return Math.abs(diff.x) < radius && Math.abs(diff.y) < radius
//   }

//   /**
//    * 检测圆与扇形碰撞（不准确）
//    */
//   public checkCircleSector(
//     sectorPos: Vec2,
//     sectorPos1: Vec2,
//     sectorPos2: Vec2,
//     sectorRadius: number,
//     sectorAngle: number,
//     circlePos: Vec2,
//     circleRadius: number,
//   ): boolean {
//     const distance = Vec2.distance(sectorPos, circlePos)
//     if (distance > sectorRadius + circleRadius) {
//       return false
//     }

//     //角度转向量
//     const rangle: number = (sectorAngle / 180) * Math.PI
//     const dirx = -Math.sin(rangle)
//     const diry = Math.cos(rangle)

//     //矩形碰撞
//     const edgeRadiusPos = sectorPos.add(v2(dirx, diry).normalize().mul(sectorRadius))
//     const posRect = v2(sectorPos.x + edgeRadiusPos.x, sectorPos.y + edgeRadiusPos.y).mul(0.5)
//     const width = Vec2.distance(sectorPos1, sectorPos2)
//     const height = sectorRadius
//     if (this.checkCircleRotateRect(circlePos, circleRadius, posRect, size(width, height), sectorAngle)) {
//       return true
//     }

//     return false // 不相交
//   }

//   /**
//    * 检测点是否在扇形区域内
//    */
//   public checkInSector(
//     posCenter: Vec2,
//     angleBegin: number,
//     angleEnd: number,
//     radiusMin: number,
//     radiusMax: number,
//     posTarget: Vec2,
//   ): boolean {
//     //距离
//     const distance: number = Vec2.distance(posCenter, posTarget)
//     if (distance < radiusMin || distance > radiusMax) {
//       return false
//     }

//     //目标角度
//     const dir0 = v2(0, 1)
//     const dir = posTarget.sub(posCenter)
//     const radian = this.getSignAngle(dir, dir0)
//     let angle = -misc.radiansToDegrees(radian)
//     angle = angle < 0 ? angle + 360 : angle
//     return !(angle < angleBegin || angle > angleEnd)
//   }

//   /**
//    * 检测圆是否与扇形区域碰撞(扇形圆心OAB，圆形C)
//    */
//   public checkCircleColliderSector(
//     sectorCenter: Vec2,
//     angleBegin: number,
//     angleEnd: number,
//     sectorRadius: number,
//     circleCenter: Vec2,
//     circleRadius: number,
//   ): boolean {
//     /** 距离 */
//     const distance: number = Vec2.distance(sectorCenter, circleCenter)
//     const between: number = sectorRadius + circleRadius
//     // 小于圆半径的，直接返回true
//     if (distance < circleRadius) {
//       return true
//     }
//     // 大于两半径和的，直接返回false
//     if (distance > between) {
//       return false
//     }

//     /** 角度 */
//     //目标角度
//     const dir0 = v2(0, 1)
//     const dir = circleCenter.sub(sectorCenter)
//     const radian = this.getSignAngle(dir, dir0)
//     let angle = -misc.radiansToDegrees(radian)
//     angle = angle < 0 ? angle + 360 : angle
//     // 圆心在扇形范围内两圆心距离小于两半径和
//     if (angle > angleBegin && angle < angleEnd && distance < between) {
//       return true
//     }
//     // 圆心不在扇形范围内
//     const pointA: Vec2 = sectorCenter.add(dir0.rotateSelf((angleBegin / 180) * Math.PI).mul(sectorRadius))
//     const pointB: Vec2 = sectorCenter.add(dir0.rotateSelf((angleEnd / 180) * Math.PI).mul(sectorRadius))
//     const ClenOA = Intersection.pointLineDistance(circleCenter, sectorCenter, pointA, true)
//     const ClenOB = Intersection.pointLineDistance(circleCenter, sectorCenter, pointB, true)
//     const min = ClenOA < ClenOB ? ClenOA : ClenOB
//     return min * min <= circleRadius * circleRadius
//   }

//   /*********** json 数据设置 ***********/

//   /**
//    * @description: 设置表里的boolean值
//    * @param {any} jsData jsData
//    * @param {string} ownProperty 属性
//    * @param defaultValue 默认返回值
//    * @return {*} 返回boolean值
//    */
//   public setBoolean(jsData: any, ownProperty: string, defaultValue = false): boolean {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const value = jsData[ownProperty]
//       const bool = Boolean(value)
//       if (bool != bool) {
//         // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "不为Bool", jsData[ownProperty]);
//         return defaultValue
//       }
//       return bool
//     }
//     // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "不存在");
//     return defaultValue
//   }

//   /**
//    * @description: 设置表里的整型数字
//    * @param {any} jsData jsData
//    * @param {string} ownProperty 属性
//    * @return {*} 为nan或者不存在这个参数的时候 返回0,否则返回整型数字
//    */
//   public setInt(jsData: any, ownProperty: string, defaultRet = 0): number {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const value = jsData[ownProperty]
//       if (value !== '') {
//         const param = parseInt(value)
//         if (param != param) {
//           // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "不为数字", jsData[ownProperty]);
//           return defaultRet
//         }
//         return param
//       }

//       return defaultRet
//     }
//     // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "不存在");
//     return defaultRet
//   }

//   public setIntArr(jsData: any, ownProperty: string, separator = '*'): number[] {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const value = jsData[ownProperty]
//       let ret = null
//       if (separator) {
//         ret = []
//         const str = String(value)
//         const arr = str.split(separator)
//         for (let i = 0; i < arr.length; i++) {
//           let ss = arr[i]
//           ss = ss.trim()
//           if (ss != '') {
//             ret.push(parseInt(ss))
//           }
//         }
//       } else if (Array.isArray(value)) {
//         ret = value
//       } else {
//         ret = []
//       }
//       return ret
//     }
//     return []
//   }

//   /**
//    * @description: 设置表里的dict
//    * @param {any} jsData
//    * @param {string} ownProperty 属性
//    * @param defaultRet 默认返回值
//    */
//   public setIntDict(jsData: any, ownProperty: string | number, defaultRet: any = {}): { [key: number]: number } {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const dict = {}
//       const value = jsData[ownProperty]
//       if (value != '') {
//         for (const key in value) {
//           const id: number = parseInt(key)
//           const lv: number = parseInt(value[id])
//           dict[id] = lv
//         }
//         return dict
//       }
//       return defaultRet
//     }
//     return defaultRet
//   }

//   /**
//    * @description: 设置表里的dict
//    * @param {any} jsData
//    * @param {string} ownProperty 属性
//    * @param defaultRet 默认返回值
//    */
//   public setStringDict(jsData: any, ownProperty: string | number, defaultRet: any = {}): { [key: number]: string } {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const dict = {}
//       const value = jsData[ownProperty]
//       if (value != '') {
//         for (const key in value) {
//           const id: number = parseInt(key)
//           const lv: string = value[id]
//           dict[id] = lv
//         }
//         return dict
//       }
//       return defaultRet
//     }
//     return defaultRet
//   }

//   /**
//    * 设置表里的dict
//    * @param jsData
//    * @param ownProperty 属性
//    * @param defaultRet 默认返回值
//    */
//   public setIntDictDict(
//     jsData: any,
//     ownProperty: string | number,
//     defaultRet: any = {},
//   ): { [key: number]: { [key: number]: number } } {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const dict: { [key: number]: { [key: number]: number } } = {}
//       const value = jsData[ownProperty]
//       if (value != '') {
//         for (const key in value) {
//           const id: number = parseInt(key)
//           const subDict: { [key: number]: number } = this.setIntDict(value, id.toString())
//           dict[id] = subDict
//         }
//         return dict
//       }
//       return defaultRet
//     }
//     return defaultRet
//   }

//   /**
//    * @description: 设置表里的dict
//    * @param {any} jsData
//    * @param {string} ownProperty 属性
//    * @param defaultRet 默认返回值
//    */
//   public setIntArrDict(jsData: any, ownProperty: string | number, defaultRet: any = {}): { [key: number]: number[] } {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const dict: { [key: number]: number[] } = {}
//       const value = jsData[ownProperty]
//       if (value != '') {
//         for (const key in value) {
//           const id: number = parseInt(key)
//           const lv: number[] = value[id]
//           dict[id] = lv
//         }
//         return dict
//       }
//       return defaultRet
//     }
//     return defaultRet
//   }

//   /**
//    * @description: 设置表里的dict
//    * @param {any} jsData
//    * @param {string} ownProperty 属性
//    * @param defaultRet 默认返回值
//    */
//   public setStrArrDict(jsData: any, ownProperty: string | number, defaultRet: any = {}): { [key: number]: string[] } {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const dict: { [key: number]: string[] } = {}
//       const value = jsData[ownProperty]
//       if (value != '') {
//         for (const key in value) {
//           const content: string[] = value[key]
//           dict[key] = content
//         }
//         return dict
//       }
//       return defaultRet
//     }
//     return defaultRet
//   }

//   /**
//    * 设置表里的dict
//    * @param jsData
//    * @param ownProperty 属性
//    * @param defaultRet 默认返回值
//    */
//   public setIntArrDictDict(
//     jsData: any,
//     ownProperty: string | number,
//     defaultRet: any = {},
//   ): { [key: number]: { [key: number]: number[] } } {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const dict: { [key: number]: { [key: number]: number[] } } = {}
//       const value = jsData[ownProperty]
//       if (value != '') {
//         for (const key in value) {
//           const id: number = parseInt(key)
//           const subDict: { [key: number]: number[] } = this.setIntArrDict(value, id.toString())
//           dict[id] = subDict
//         }
//         return dict
//       }
//       return defaultRet
//     }
//     return defaultRet
//   }

//   /**
//    * @description: 设置表里的数字
//    * @param {any} jsData jsData
//    * @param {string} ownProperty 属性
//    * @return {*} 为nan或者不存在这个参数的时候 返回0,否则返回数字
//    */
//   public setNum(jsData: any, ownProperty: string, defaultValue = 0): number {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const value = jsData[ownProperty]
//       const num = Number(value)
//       if (num != num) {
//         // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "不为数字", jsData[ownProperty]);
//         return defaultValue
//       }
//       return num
//     }
//     // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "不存在");
//     return defaultValue
//   }

//   /**
//    * @description: 设置表里的数组
//    * @param {any} jsData
//    * @param {string} ownProperty 属性
//    * @param {*} separator 切分符号,默认是 "*"
//    * @param {number} hopeLength 希望这个数组的长度,如果导出的长度不等于这个长度会warn提示
//    * @return {*} 分隔符，存储数据使用改的话，这里要是null
//    */
//   public setNumArr(jsData: any, ownProperty: string, hopeLength?: number, separator = '*'): number[] {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const value = jsData[ownProperty]
//       const str = value
//       let arr = null
//       if (separator) {
//         arr = DYTools.stringToNumber(str, separator)
//       } else {
//         arr = str
//       }
//       if (arr.length == 0) {
//         // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "的数组长度为0");
//       }
//       if (hopeLength && arr.length != hopeLength) {
//         // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "的数组长度不为", hopeLength);
//       }
//       return arr
//     }
//     // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "不存在");
//     return []
//   }

//   /** number[][] */
//   public setNumArrD(jsData: any, ownProperty: string, sp1 = '#', sp2 = '*'): number[][] {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const value = jsData[ownProperty]
//       const str = value
//       let arr = null
//       if (sp1) {
//         arr = []
//         const tmpArr = this.setStringArr(jsData, ownProperty, sp1)
//         for (let i = 0; i < tmpArr.length; i++) {
//           const tmp = tmpArr[i]
//           if (tmp && tmp != '') {
//             const a = DYTools.stringToNumber(tmp, sp2)
//             arr.push(a)
//           }
//         }
//       } else {
//         arr = str
//       }
//       return arr
//     }
//     return []
//   }

//   /**
//    * @description: 设置表里的dict
//    * @param {any} jsData
//    * @param {string} ownProperty 属性
//    */
//   public setNumDict(jsData: any, ownProperty: string): {} {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const dict = {}
//       const value = jsData[ownProperty]
//       for (const key in value) {
//         const id = Number(key)
//         const lv = Number(value[id])
//         dict[id] = lv
//       }
//       return dict
//     }
//     return {}
//   }

//   /**
//    * 设置vec坐标数据
//    * @param jsData
//    * @param ownProperty
//    * @param hopeLength
//    * @param separator
//    * @returns
//    */
//   public setVec2(jsData: any, ownProperty: string, separator = '*'): Vec2 {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const value = jsData[ownProperty]
//       const str = value
//       const pos = DYTools.stringToPoint(str, separator)
//       return pos
//     }
//     // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "不存在");
//     return Vec2.ZERO
//   }

//   public setVec2Arr(jsData: any, ownProperty: string): Vec2[] {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const value: string = jsData[ownProperty]
//       const tmpArr = []
//       if (value != '') {
//         const arr = value.split('#')
//         for (let i = 0; i < arr.length; i++) {
//           const pos = DYTools.stringToPoint(arr[i], '*')
//           tmpArr.push(pos)
//         }
//       }
//       return tmpArr
//     }
//     // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "不存在");
//     return []
//   }

//   /** item数量 */
//   public setItemArr(jsData: any, ownProperty: string): { id: number; count: number }[] {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const value: string = jsData[ownProperty]
//       const tmpArr = []
//       if (value != '') {
//         const arr = value.split('#')
//         for (let i = 0; i < arr.length; i++) {
//           const tmp = DYTools.stringToNumber(arr[i]) // arr[i].split('*');
//           if (tmp.length > 1) {
//             tmpArr.push({ id: tmp[0], count: tmp[1] })
//           }
//         }
//       }
//       return tmpArr
//     }
//     // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "不存在");
//     return []
//   }

//   /**
//    * @description: 设置表里的数组
//    * @param {any} jsData
//    * @param {string} ownProperty 属性
//    * @return {*} 返回字符串
//    */
//   public setString(jsData: any, ownProperty: string): string {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const value = jsData[ownProperty]
//       return String(value)
//     }
//     // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "不存在");
//     return ''
//   }

//   /**
//    * @description: 设置表里字符串数组
//    * @param {any} jsData
//    * @param {string} ownProperty 属性
//    * @param {string} separator 切分符 默认为 "*"
//    * @param {number} hopeLength 希望这个数组的长度,如果导出的长度不等于这个长度会warn提示
//    * @return {*}除了没有这个属性返回[],否则返回表里配置的数组
//    */
//   public setStringArr(jsData: any, ownProperty: string, separator = '*', hopeLength?: number): string[] {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const value = jsData[ownProperty]
//       const str = String(value)
//       if (str == '') {
//         return []
//       }
//       if (separator) {
//         const arr = str.split(separator)
//         if (arr.length == 0) {
//           // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "的数组长度为0");
//         }
//         if (hopeLength && arr.length != hopeLength) {
//           // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "的数组长度不为", hopeLength);
//         }
//         return arr
//       }
//       if (Array.isArray(value)) {
//         return value
//       }
//       return []
//     }
//     // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "不存在");
//     return []
//   }

//   /**
//    * @description: 设置表里的颜色
//    * @param {any} jsData
//    * @param {string} ownProperty 属性
//    * @return {*} 返回字符串
//    */
//   public setColor(jsData: any, ownProperty: string, separator = '*'): Color {
//     let color = color(255, 255, 255)
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const value = jsData[ownProperty]
//       const str = String(value)
//       if (str != '') {
//         const arr = str.split(separator)
//         if (arr.length == 3) {
//           color = color(Number(arr[0]), Number(arr[1]), Number(arr[2]))
//         }
//       }
//     }

//     return color
//   }

//   /** 设置自定义数据 */
//   public setJsonData<T>(jsData: any, ownProperty: string, data: new () => T): T {
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const value = jsData[ownProperty]
//       const ret = new data()
//       ret['loadJson'](value)
//       return ret
//     }
//     // console.warn(this.tableName, "表中 id为", this.id, "的", ownProperty, "不存在");
//     return null
//   }

//   public setJsonDataArr<T>(jsData: any, ownProperty: string, temp: new () => T) {
//     const arr = []
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const values = jsData[ownProperty]
//       if (values && values.length > 0) {
//         for (let i = 0; i < values.length; i++) {
//           const data = new temp()
//           data['loadJson'](values[i])
//           arr.push(data)
//         }
//       }
//     }

//     return arr
//   }

//   /** 字典格式 */
//   public setJsonDataDict<T>(jsData: any, ownProperty: string, temp: new () => T) {
//     const dict: { [key: number]: T } = {}
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const param = jsData[ownProperty]
//       for (const key in param) {
//         const id: number = parseInt(key)
//         const tmp = param[key]
//         if (tmp) {
//           const data = new temp()
//           data['loadJson'](tmp)
//           dict[id] = data
//         } else {
//           DYTools.error('error json data dict ', ownProperty)
//         }
//       }
//     }

//     return dict
//   }

//   public setJsonDataArrDict<T>(jsData: any, ownProperty: string, temp: new () => T): { [key: number]: T[] } {
//     const dict: { [key: number]: T[] } = {}
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const param = jsData[ownProperty]
//       for (const key in param) {
//         const id: number = parseInt(key)
//         const arr: T[] = []
//         const values = param[key]
//         if (values) {
//           for (let i = 0; i < values.length; i++) {
//             const data = new temp()
//             data['loadJson'](values[i])
//             arr.push(data)
//           }
//         }
//         dict[id] = arr
//       }
//     } else {
//       DYTools.warn('error json data array dict ', ownProperty)
//     }

//     return dict
//   }

//   /** 二维字典 */
//   public setJsonDataDictDict<T>(
//     jsData: any,
//     ownProperty: string,
//     temp: new () => T,
//   ): { [key: number]: { [key: number]: T } } {
//     const dict: { [key: number]: { [key: number]: T } } = {}
//     if (jsData.hasOwnProperty(ownProperty)) {
//       const param = jsData[ownProperty]
//       for (const key in param) {
//         const id: number = parseInt(key)
//         const values = param[key]
//         if (values) {
//           dict[id] = this.setJsonDataDict(values, ownProperty, temp)
//         }
//       }
//     } else {
//       DYTools.error('error json data dict dict ', ownProperty)
//     }

//     return dict
//   }

//   /**
//    * 获取一个从0到n的整数数组
//    */
//   public getIntArr(end: number, start = 0) {
//     const arr: number[] = []
//     for (let i = start; i <= end; i++) {
//       arr.push(i)
//     }
//     return arr
//   }

//   /*********** AES 加解密 ***********/
//   private _aesKey1 = 'mdy8155zs2619lfm'

//   private _aesKey2 = 's9mnbdk1giu2e3wn'

//   public initAES() {
//     this._aesKey1 = 'mdy8155zs2619lfm'
//     this._aesKey2 = 's9mnbdk1giu2e3wn'
//   }

//   public AESEncode(data: any): string {
//     const key = CryptoJS.enc.Latin1.parse(this._aesKey1)
//     const iv = CryptoJS.enc.Latin1.parse(this._aesKey2)

//     //加密
//     const encrypted = CryptoJS.AES.encrypt(data, key, {
//       iv,
//       mode: CryptoJS.mode.CBC,
//       padding: CryptoJS.pad.ZeroPadding,
//     })
//     // Tools_Instance.log("加密结果："+encrypted.toString());
//     return encrypted.toString()
//   }

//   public AESDecode(data: string, dec = true) {
//     const key = CryptoJS.enc.Latin1.parse(this._aesKey1)
//     const iv = CryptoJS.enc.Latin1.parse(this._aesKey2)
//     const decrypted = CryptoJS.AES.decrypt(data, key, {
//       iv,
//       mode: CryptoJS.mode.CBC,
//       padding: CryptoJS.pad.ZeroPadding,
//     })
//     let content: string
//     if (dec) {
//       try {
//         // let uncompressedLen = lz4.calcUncompressedLen(decrypted.words);
//         // let decompressed = new Uint8Array(uncompressedLen);
//         const bytes = this.wordArrayToArrayBuffer(decrypted)
//         const decompressed = decompress(bytes)
//         content = this.utf8ArrayToStr(decompressed)
//         return content
//       } catch (e) {
//         // console.warn(`decompress data fail, error: ${e}`);
//       }
//     }
//     // 不解压，直接解析
//     content = CryptoJS.enc.Utf8.stringify(decrypted)
//     // Tools_Instance.log("解密结果："+content);
//     return content
//   }

//   encryptNum(value: number): string {
//     if (value == null) return null
//     return this.encryptString(value.toString())
//   }

//   decryptNum(encryptedValue: string): number {
//     if (encryptedValue == null) return null
//     return parseFloat(this.decryptString(encryptedValue)) // 缩小数值还原为浮点数
//   }

//   encryptBool(value: boolean): string {
//     if (value == null) return null
//     return this.encryptNum(value ? 1 : 0)
//   }

//   decryptBool(encryptedValue: string, defaultV = false): boolean {
//     if (encryptedValue == null) return defaultV
//     return this.decryptNum(encryptedValue) > 0 // 缩小数值还原为浮点数
//   }

//   // 偏移量（可以是任意整数，根据需要调整）
//   private offset = 3

//   /**
//    * 对单个字符串进行加密：每个字符的 ASCII 值偏移
//    * @param str - 需要加密的字符串
//    * @returns 加密后的字符串
//    */
//   encryptString(str: string): string {
//     if (str == null) return null
//     let encryptedStr = ''
//     for (let i = 0; i < str.length; i++) {
//       // 对每个字符的 charCode（ASCII）值进行偏移
//       encryptedStr += String.fromCharCode(str.charCodeAt(i) + this.offset)
//     }
//     return encryptedStr
//   }

//   /**
//    * 对单个加密字符串进行解密：每个字符的 ASCII 值反向偏移
//    * @param str - 需要解密的加密字符串
//    * @returns 解密后的原始字符串
//    */
//   decryptString(str: string): string {
//     if (str == null) return null
//     let decryptedStr = ''
//     for (let i = 0; i < str.length; i++) {
//       // 对每个字符的 charCode（ASCII）值反向偏移
//       decryptedStr += String.fromCharCode(str.charCodeAt(i) - this.offset)
//     }
//     return decryptedStr
//   }

//   /**
//    * 对字符串数组进行加密：每个字符串的字符进行加密
//    * @param arr - 需要加密的字符串数组
//    * @returns 加密后的字符串数组
//    */
//   encryptNumArray(arr: number[]): string[] {
//     const encryptedArr: string[] = []
//     for (let i = 0; i < arr.length; i++) {
//       encryptedArr[i] = this.encryptNum(arr[i])
//     }
//     return encryptedArr
//   }

//   /**
//    * 对字符串数组进行解密：每个加密字符串的字符进行解密
//    * @param arr - 需要解密的加密字符串数组
//    * @returns 解密后的原始字符串数组
//    */
//   decryptNumArray(arr: string[]): number[] {
//     const decryptedArr: number[] = []
//     for (let i = 0; i < arr.length; i++) {
//       decryptedArr[i] = this.decryptNum(arr[i])
//     }
//     return decryptedArr
//   }

//   /**
//    * 对字符串数组进行加密：每个字符串的字符进行加密
//    * @param arr - 需要加密的字符串数组
//    * @returns 加密后的字符串数组
//    */
//   encryptStringArray(arr: string[]): string[] {
//     const encryptedArr: string[] = []
//     for (let i = 0; i < arr.length; i++) {
//       encryptedArr[i] = this.encryptString(arr[i])
//     }
//     return encryptedArr
//   }

//   /**
//    * 对字符串数组进行解密：每个加密字符串的字符进行解密
//    * @param arr - 需要解密的加密字符串数组
//    * @returns 解密后的原始字符串数组
//    */
//   decryptStringArray(arr: string[]): string[] {
//     const decryptedArr: string[] = []
//     for (let i = 0; i < arr.length; i++) {
//       decryptedArr[i] = this.decryptString(arr[i])
//     }
//     return decryptedArr
//   }

//   public wordArrayToArrayBuffer(wordArray) {
//     const { words } = wordArray
//     const { sigBytes } = wordArray
//     const u8 = new Uint8Array(sigBytes)
//     for (let i = 0; i < sigBytes; i += 1) {
//       u8[i] = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
//     }
//     return u8
//   }

//   public utf8ArrayToStr(array) {
//     let out = ''
//     let i
//     const len = array.length
//     let c
//     let char2
//     let char3

//     i = 0
//     while (i < len) {
//       c = array[i++]
//       switch (c >> 4) {
//         case 0:
//         case 1:
//         case 2:
//         case 3:
//         case 4:
//         case 5:
//         case 6:
//         case 7:
//           // 0xxxxxxx
//           out += String.fromCharCode(c)
//           break
//         case 12:
//         case 13:
//           // 110x xxxx   10xx xxxx
//           char2 = array[i++]
//           out += String.fromCharCode(((c & 0x1f) << 6) | (char2 & 0x3f))
//           break
//         case 14:
//           // 1110 xxxx  10xx xxxx  10xx xxxx
//           char2 = array[i++]
//           char3 = array[i++]
//           out += String.fromCharCode(((c & 0x0f) << 12) | ((char2 & 0x3f) << 6) | ((char3 & 0x3f) << 0))
//           break
//       }
//     }

//     return out
//   }

//   private _mapAesKey1 = 'ALf023F1fj3Feh23'

//   private _mapAesKey2 = 'LF318njkFGIY8959'

//   public MapAESEncode(data: any) {
//     const key = CryptoJS.enc.Latin1.parse(this._mapAesKey1)
//     const iv = CryptoJS.enc.Latin1.parse(this._mapAesKey2)

//     //加密
//     const encrypted = CryptoJS.AES.encrypt(data, key, {
//       iv,
//       mode: CryptoJS.mode.CBC,
//       padding: CryptoJS.pad.ZeroPadding,
//     })
//     // Tools_Instance.log("加密结果："+encrypted.toString());
//     return encrypted.toString()
//   }

//   public MAPAESDecode(data: string) {
//     const key = CryptoJS.enc.Latin1.parse(this._mapAesKey1)
//     const iv = CryptoJS.enc.Latin1.parse(this._mapAesKey2)
//     const decrypted = CryptoJS.AES.decrypt(data, key, {
//       iv,
//       mode: CryptoJS.mode.CBC,
//       padding: CryptoJS.pad.ZeroPadding,
//     })
//     const content = CryptoJS.enc.Utf8.stringify(decrypted)
//     // Tools_Instance.log("解密结果："+content);
//     return content
//   }

//   /********* RSA 加解密 **********/
//   // private _rsaObject: any = null;
//   // // m&d(y.?.<snake-1;'2j29h10ee1o2art01t
//   // private _rsaPublickKey: string = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKbUlqg4HAWjAvLzEmX5pVVyBuRW+oSOfPVubZTveDwzK8yi+YBLfsZsmGLkQsEAHAnAUHUAh1Rcl4WL0YU9i18CAwEAAQ==";
//   // private _rsaPrivatekKey: string = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAptSWqDgcBaMC8vMSZfmlVXIG5Fb6hI589W5tlO94PDMrzKL5gEt+xmyYYuRCwQAcCcBQdQCHVFyXhYvRhT2LXwIDAQABAkA5N544MY5CzKa9Rmqf+OAgjwwYElC3V9s5ndcNhpgZJPG6/nSiQMak06K4sLPxAoKIX1Yh0P9FeNJCYgCcQBexAiEA2sKxrj1Oc+XKgDy5x49B7pi7GAq+6VV8dy7kOCNNOGkCIQDDOti7M0FHFiMy1K5i5H6kIckiq8Fh99Agk0n6auTshwIgPH2duDqHmRCvoCoqjP4WEy30fj9qbwcOdb5nqQZJ8hECIAy9qWlGJgtymWd2086mZNFnVw4JMXyoRI/rrNdH5Jq/AiEA0lnh6FaneKHxxWPsGCuYbMFDqxz/tgoc9AisrLl+A8I=";
//   // public initRSA() {
//   //     this._rsaObject = new JSEncrypt();
//   //     this._rsaObject.setPublicKey('-----BEGIN PUBLIC KEY-----' + this._rsaPublickKey + '-----END PUBLIC KEY-----');
//   //     this._rsaObject.setPrivateKey('-----BEGIN RSA PRIVATE KEY-----' + this._rsaPrivatekKey + '-----END RSA PRIVATE KEY-----');
//   // }
//   // public RSAEncrypy(str: string): string {
//   //     if (!this._rsaObject) {
//   //         this.initRSA();
//   //     }
//   //     let encrypted = this._rsaObject.encrypt(str);
//   //     //DYTools.log('加密前数据:%o', str);
//   //     //DYTools.log('加密后数据:%o', encrypted);
//   //     return encrypted;
//   // }
//   // public RSADecrypt(str: string): string {
//   //     if (!this._rsaObject) {
//   //         this.initRSA();
//   //     }
//   //     let uncrypted = this._rsaObject.decrypt(str);
//   //     //DYTools.log('解密后数据:%o', JSON.parse(uncrypted));
//   //     return uncrypted;
//   // }

//   //生成随机 GUID 数
//   public guid(): string {
//     function S4() {
//       return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
//     }
//     return `${S4() + S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`
//   }

//   /********* Cocos引擎工具方法 **********/

//   /**
//    * 递归设置阶段透明度
//    * @param node 节点
//    * @param opacity 透明度
//    */
//   public setOpacityRecursively(node: Node, opacity: number) {
//     node.opacity = opacity
//     const { children } = node
//     for (let i = 0; i < children.length; i++) {
//       this.setOpacityRecursively(children[i], opacity)
//     }
//   }

//   /**
//    * 递归设置透明度动画
//    * @param node 节点
//    * @param opacity 透明度
//    * @param delay 延迟
//    * @param duration 动画时长
//    */
//   public setOpacityTweenRecursively(node: Node, opacity: number, delay: number, duration: number): Tween {
//     const ret = tween(node).delay(delay).to(duration, { opacity }).start()

//     for (let i = 0; i < node.children.length; i++) {
//       this.setOpacityTweenRecursively(node.children[i], opacity, delay, duration)
//     }

//     return ret
//   }

//   /**
//    * 调用原生方法
//    * 无参数，无返回值
//    * @param className 类名
//    * @param funcName 方法名
//    */
//   public callNativeFunc(className: string, funcName: string): void {
//     if (CC_JSB) {
//       if (sys.os == sys.OS_IOS) {
//         // @ts-ignore
//         jsb.reflection.callStaticMethod(className, `${funcName}`)
//       } else if (sys.os == sys.OS_ANDROID) {
//         // @ts-ignore
//         jsb.reflection.callStaticMethod(`org/cocos2dx/javascript/service/${className}`, funcName, '()V')
//       }
//     }
//   }

//   /**
//    * 调用原生方法
//    * 一个字符串参数，无返回值
//    * @param className 类名
//    * @param funcName 方法名
//    * @param strArg 字符串参数
//    */
//   public callNativeFuncWithStringParam(className: string, funcName: string, strArg: string): void {
//     if (CC_JSB) {
//       if (sys.os == sys.OS_IOS) {
//         // @ts-ignore
//         jsb.reflection.callStaticMethod(className, `${funcName}:`, strArg)
//       } else if (sys.os == sys.OS_ANDROID) {
//         // @ts-ignore
//         jsb.reflection.callStaticMethod(
//           `org/cocos2dx/javascript/service/${className}`,
//           funcName,
//           '(Ljava/lang/String;)V',
//           strArg,
//         )
//       }
//     }
//   }

//   /**
//    * 调用原生方法
//    * 一个字符串参数，无返回值
//    * @param className 类名
//    * @param funcName 方法名
//    * @param boolArg Boolean型参数
//    */
//   public callNativeFuncWithBooleanParam(className: string, funcName: string, boolArg: boolean): void {
//     if (CC_JSB) {
//       if (sys.os == sys.OS_IOS) {
//         // @ts-ignore
//         jsb.reflection.callStaticMethod(className, `${funcName}:`, boolArg)
//       } else if (sys.os == sys.OS_ANDROID) {
//         // @ts-ignore
//         jsb.reflection.callStaticMethod(`org/cocos2dx/javascript/service/${className}`, funcName, '(Z)V', boolArg)
//       }
//     }
//   }
//   /**
//    * 将一个对象转换为不带 URI 编码的查询字符串。
//    * 键和值中的特殊字符不会被编码。
//    *
//    * @param obj - 需要被转换的对象。
//    * @returns 对象的查询字符串表示形式。
//    */
//   public objectToQueryString(obj: { [key: string]: any }): string {
//     return Object.entries(obj)
//       .map(([key, value]) => `${key}=${value}`)
//       .join('&')
//   }

//   // /**
//   //  * 将一个不带 URI 编码的查询字符串转换为对象。
//   //  * 键和值中的特殊字符不会被解码。
//   //  *
//   //  * @param queryString - 需要被转换的查询字符串。
//   //  * @returns 查询字符串的对象表示形式。
//   //  */
//   // public  queryStringToObject(queryString: string): {[key: string]: string} {
//   //     return queryString.split('&')
//   //         .map(part => part.split('='))
//   //         .reduce((obj, [key, value]) => ({
//   //             ...obj,
//   //             [key]: value,
//   //         }), {});
//   // }

//   /**
//    * 横向移动的ScrollView，若内容长度小于ScrollView长度，则居中显示
//    * @param scrollView
//    * @param layout
//    */
//   public checkHorizontalScrollViewContentMiddle(scrollView: ScrollView, layout: Layout) {
//     layout.updateLayout()
//     if (layout.node.width <= scrollView.node.width) {
//       scrollView.enabled = false
//       layout.node.x = scrollView.node.width / 2 - layout.node.width / 2
//     } else {
//       layout.node.x = 0
//       scrollView.enabled = true
//     }
//   }

//   /** Node播放旋转动画 */
//   public rotateForever(node: Node, angleSpeed = 60) {
//     if (node?.active) {
//       Tween.stopAllByTarget(node)
//       tween(node).by(1, { angle: angleSpeed }).union().repeatForever().start()
//     }
//   }

//   /** 两个向量的角度 */
//   public getAngleBy2Dir(dir: Vec2, dir0: Vec2): number {
//     let radian = 0
//     if (dir0 != dir) {
//       if (dir.magSqr() !== 0 && dir0.magSqr() !== 0) {
//         radian = this.getSignAngle(dir, dir0)
//       }
//     }
//     const angle = misc.radiansToDegrees(radian)

//     return angle
//   }

//   _cache1V2 = v2()

//   _cache2V2 = v2()

//   public getSignAngle(dir0: Vec2, dir1: Vec2): number {
//     if ((dir0.x == 0 && dir0.y == 0) || (dir1.x == 0 && dir1.y == 0)) {
//       return 0
//     }
//     if (dir0 instanceof Vec3) {
//       this._cache1V2.x = dir0.x
//       this._cache1V2.y = dir0.y
//       dir0 = this._cache1V2
//     }
//     if (dir1 instanceof Vec3) {
//       this._cache2V2.x = dir1.x
//       this._cache2V2.y = dir1.y
//       dir1 = this._cache2V2
//     }
//     return dir0.signAngle(dir1)
//   }

//   /**
//    * 格式化日期 替换所有可能的分隔符为 '/'
//    * @param dateStr {String}
//    * @returns {Date}
//    */
//   public transformDate(dateStr: string | Date) {
//     // 检查是否为数字或只包含数字的字符串
//     if (typeof dateStr === 'number' || (typeof dateStr === 'string' && /^\d+$/.test(dateStr))) {
//       return dateStr
//     }
//     // 检查是否为 Date 对象
//     if (dateStr instanceof Date) {
//       return dateStr
//     }
//     // 替换所有可能的分隔符为 '/'，并返回结果字符串
//     return dateStr.replace(/[-.]/g, '/')
//   }

//   /**
//    * 根据key对数组进行分组，返回Map
//    * @param arr
//    * @param key
//    */
//   public groupByToMap<T, K>(arr: T[], key: (item: T) => K): Map<K, T[]> {
//     return arr.reduce((acc, item) => {
//       const groupKey = key(item)
//       if (!acc.has(groupKey)) {
//         acc.set(groupKey, [])
//       }
//       acc.get(groupKey)!.push(item)
//       return acc
//     }, new Map<K, T[]>())
//   }

//   // 过滤数据中不需要存储的字段
//   public filter(data: Record<string, any>, excludeKeys: string[]): Record<string, any> {
//     const filteredData: Record<string, any> = {}
//     for (const key in data) {
//       if (!excludeKeys.includes(key)) {
//         filteredData[key] = data[key]
//       }
//     }
//     return filteredData
//   }
// }

// export const DYTools = Tools.instance
